Skip to content

Instantly share code, notes, and snippets.

@stephenjudkins
Created May 22, 2009 17:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stephenjudkins/116269 to your computer and use it in GitHub Desktop.
Save stephenjudkins/116269 to your computer and use it in GitHub Desktop.
the most beautiful ruby code ever produced.
MW_PARSER_VERSION = "1.6.1"
RLH_FOR_UPDATE = 1
OT_HTML = 1
OT_WIKI = 2
OT_MSG = 3
OT_PREPROCESS = 4
SFH_NO_HASH = 1
STRIP_COMMENTS = "HTMLCommentStrip"
HTTP_PROTOCOLS = "http:\\/\\/|https:\\/\\/"
EXT_LINK_URL_CLASS = "[^][<>\"\\x00-\\x20\\x7F]"
EXT_LINK_TEXT_CLASS = "[^\\]\\x0a\\x0d]"
EXT_IMAGE_FNAME_CLASS = "[A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]"
EXT_IMAGE_EXTENSIONS = "gif|png|jpg|jpeg"
EXT_LINK_BRACKETED = ("/\\[(\\b(" + (wfUrlProtocols + (")" + (EXT_LINK_URL_CLASS + ("+) *(" + (EXT_LINK_TEXT_CLASS + "*?)\\]/S"))))))
EXT_IMAGE_REGEX = ("/^(" + (HTTP_PROTOCOLS + (")(" + (EXT_LINK_URL_CLASS + ("+)\\/(" + (EXT_IMAGE_FNAME_CLASS + ("+)\\.((?i)" + (EXT_IMAGE_EXTENSIONS + ")$/S"))))))))
MW_COLON_STATE_TEXT = 0
MW_COLON_STATE_TAG = 1
MW_COLON_STATE_TAGSTART = 2
MW_COLON_STATE_CLOSETAG = 3
MW_COLON_STATE_TAGSLASH = 4
MW_COLON_STATE_COMMENT = 5
MW_COLON_STATE_COMMENTDASH = 6
MW_COLON_STATE_COMMENTDASHDASH = 7
class Parser
attr_accessor(:mTagHooks)
attr_accessor(:mFunctionHooks)
attr_accessor(:mFunctionSynonyms)
attr_accessor(:mVariables)
attr_accessor(:mOutput)
attr_accessor(:mAutonumber)
attr_accessor(:mDTopen)
attr_accessor(:mStripState)
attr_accessor(:mIncludeCount)
attr_accessor(:mArgStack)
attr_accessor(:mLastSection)
attr_accessor(:mInPre)
attr_accessor(:mInterwikiLinkHolders)
attr_accessor(:mLinkHolders)
attr_accessor(:mUniqPrefix)
attr_accessor(:mIncludeSizes)
attr_accessor(:mDefaultSort)
attr_accessor(:mTemplates)
attr_accessor(:mTemplatePath)
attr_accessor(:mOptions)
attr_accessor(:mTitle)
attr_accessor(:mOutputType)
attr_accessor(:ot)
attr_accessor(:mRevisionId)
attr_accessor(:mRevisionTimestamp)
attr_accessor(:mRevIdForTs)
def Parser
@mTagHooks = []
@mFunctionHooks = []
@mFunctionSynonyms = { 0 => ([]), 1 => ([]) }
@mFirstCall = true
end
def firstCallInit
return nil if (not @mFirstCall)
wfProfileIn("Parser::firstCallInit")
(php_global(:wgAllowDisplayTitle)
php_global(:wgAllowSlowParserFunctions))
self.setHook("pre", [self, "renderPreTag"])
self.setFunctionHook("int", ["CoreParserFunctions", "intFunction"], SFH_NO_HASH)
self.setFunctionHook("ns", ["CoreParserFunctions", "ns"], SFH_NO_HASH)
self.setFunctionHook("urlencode", ["CoreParserFunctions", "urlencode"], SFH_NO_HASH)
self.setFunctionHook("lcfirst", ["CoreParserFunctions", "lcfirst"], SFH_NO_HASH)
self.setFunctionHook("ucfirst", ["CoreParserFunctions", "ucfirst"], SFH_NO_HASH)
self.setFunctionHook("lc", ["CoreParserFunctions", "lc"], SFH_NO_HASH)
self.setFunctionHook("uc", ["CoreParserFunctions", "uc"], SFH_NO_HASH)
self.setFunctionHook("localurl", ["CoreParserFunctions", "localurl"], SFH_NO_HASH)
self.setFunctionHook("localurle", ["CoreParserFunctions", "localurle"], SFH_NO_HASH)
self.setFunctionHook("fullurl", ["CoreParserFunctions", "fullurl"], SFH_NO_HASH)
self.setFunctionHook("fullurle", ["CoreParserFunctions", "fullurle"], SFH_NO_HASH)
self.setFunctionHook("formatnum", ["CoreParserFunctions", "formatnum"], SFH_NO_HASH)
self.setFunctionHook("grammar", ["CoreParserFunctions", "grammar"], SFH_NO_HASH)
self.setFunctionHook("plural", ["CoreParserFunctions", "plural"], SFH_NO_HASH)
self.setFunctionHook("numberofpages", ["CoreParserFunctions", "numberofpages"], SFH_NO_HASH)
self.setFunctionHook("numberofusers", ["CoreParserFunctions", "numberofusers"], SFH_NO_HASH)
self.setFunctionHook("numberofarticles", ["CoreParserFunctions", "numberofarticles"], SFH_NO_HASH)
self.setFunctionHook("numberoffiles", ["CoreParserFunctions", "numberoffiles"], SFH_NO_HASH)
self.setFunctionHook("numberofadmins", ["CoreParserFunctions", "numberofadmins"], SFH_NO_HASH)
self.setFunctionHook("numberofedits", ["CoreParserFunctions", "numberofedits"], SFH_NO_HASH)
self.setFunctionHook("language", ["CoreParserFunctions", "language"], SFH_NO_HASH)
self.setFunctionHook("padleft", ["CoreParserFunctions", "padleft"], SFH_NO_HASH)
self.setFunctionHook("padright", ["CoreParserFunctions", "padright"], SFH_NO_HASH)
self.setFunctionHook("anchorencode", ["CoreParserFunctions", "anchorencode"], SFH_NO_HASH)
self.setFunctionHook("special", ["CoreParserFunctions", "special"])
self.setFunctionHook("defaultsort", ["CoreParserFunctions", "defaultsort"], SFH_NO_HASH)
if wgAllowDisplayTitle then
self.setFunctionHook("displaytitle", ["CoreParserFunctions", "displaytitle"], SFH_NO_HASH)
end
if wgAllowSlowParserFunctions then
self.setFunctionHook("pagesinnamespace", ["CoreParserFunctions", "pagesinnamespace"], SFH_NO_HASH)
end
self.initialiseVariables
@mFirstCall = false
wfProfileOut("Parser::firstCallInit")
end
def clearState
wfProfileIn("Parser::clearState")
self.firstCallInit if @mFirstCall
@mOutput = ParserOutput.new
@mAutonumber = 0
@mLastSection = ""
@mDTopen = false
@mIncludeCount = []
@mStripState = StripState.new
@mArgStack = []
@mInPre = false
@mInterwikiLinkHolders = { "texts" => ([]), "titles" => ([]) }
@mLinkHolders = { "namespaces" => ([]), "dbkeys" => ([]), "queries" => ([]), "texts" => ([]), "titles" => ([]) }
@mRevisionTimestamp = @mRevisionId = nil
@mUniqPrefix = ("\aUNIQ" + Parser.getRandomString)
@mTemplates = []
@mTemplatePath = []
@mShowToc = true
@mForceTocPosition = false
@mIncludeSizes = { "pre-expand" => 0, "post-expand" => 0, "arg" => 0 }
@mDefaultSort = false
wfRunHooks("ParserClearState", [self])
wfProfileOut("Parser::clearState")
end
def setOutputType(ot)
@mOutputType = ot
@ot = { "html" => ((ot == OT_HTML)), "wiki" => ((ot == OT_WIKI)), "msg" => ((ot == OT_MSG)), "pre" => ((ot == OT_PREPROCESS)) }
end
def uniqPrefix
return @mUniqPrefix
end
def parse(text, title, options, linestart = true, clearState = true, revid = nil)
(php_global(:wgUseTidy)
php_global(:wgAlwaysUseTidy)
php_global(:wgContLang))
fname = ("Parser::parse-" + wfGetCaller)
wfProfileIn("Parser::parse")
wfProfileIn(fname)
self.clearState if clearState
@mOptions = options
@mTitle = title
oldRevisionId = @mRevisionId
oldRevisionTimestamp = @mRevisionTimestamp
if (not (revid == nil)) then
@mRevisionId = revid
@mRevisionTimestamp = nil
end
self.setOutputType(OT_HTML)
wfRunHooks("ParserBeforeStrip", [self, text, @mStripState])
text = self.strip(text, @mStripState)
wfRunHooks("ParserAfterStrip", [self, text, @mStripState])
text = self.internalParse(text)
text = @mStripState.unstripGeneral(text)
fixtags = { "/(.) (?=\\?|:|;|!|\\302\\273)/" => "\\1&nbsp;\\2", "/(\\302\\253) /" => "\\1&nbsp;" }
text = preg_replace(array_keys(fixtags), array_values(fixtags), text)
text = self.doBlockLevels(text, linestart)
self.replaceLinkHolders(text)
text = wgContLang.parserConvert(text, self)
text = @mStripState.unstripNoWiki(text)
wfRunHooks("ParserBeforeTidy", [self, text])
text = Sanitizer.normalizeCharReferences(text)
if ((wgUseTidy and @mOptions.mTidy) or wgAlwaysUseTidy) then
text = Parser.tidy(text)
else
tidyregs = { "/(<([bi])>)(<([bi])>)?([^<]*)(<\\/?a[^<]*>)([^<]*)(<\\/\\4>)?(<\\/\\2>)/" => "\\1\\3\\5\\8\\9\\6\\1\\3\\7\\8\\9", "/(<a[^>]+>)([^<]*)(<a[^>]+>[^<]*)<\\/a>(.*)<\\/a>/" => "\\1\\2</a>\\3</a>\\1\\4</a>", "/(<([aib]) [^>]+>)([^<]*)(<div([^>]*)>)(.*)(<\\/div>)([^<]*)(<\\/\\2>)/" => "\\1\\3&lt;div\\5&gt;\\6&lt;/div&gt;\\8\\9", "/<([bi])><\\/\\1>/" => "" }
text = preg_replace(array_keys(tidyregs), array_values(tidyregs), text)
end
wfRunHooks("ParserAfterTidy", [self, text])
if (max(@mIncludeSizes) > 1500) then
max = @mOptions.getMaxIncludeSize
text = (text + ("<!-- \nPre-expand include size: " + (@mIncludeSizes["pre-expand"] + (" bytes\nPost-expand include size: " + (@mIncludeSizes["post-expand"] + (" bytes\nTemplate argument size: " + (@mIncludeSizes["arg"] + (" bytes\nMaximum: " + (max + " bytes\n-->\n")))))))))
end
@mOutput.setText(text)
@mRevisionId = oldRevisionId
@mRevisionTimestamp = oldRevisionTimestamp
wfProfileOut(fname)
wfProfileOut("Parser::parse")
return @mOutput
end
def recursiveTagParse(text)
wfProfileIn("Parser::recursiveTagParse")
wfRunHooks("ParserBeforeStrip", [self, text, @mStripState])
text = self.strip(text, @mStripState)
wfRunHooks("ParserAfterStrip", [self, text, @mStripState])
text = self.internalParse(text)
wfProfileOut("Parser::recursiveTagParse")
return text
end
def preprocess(text, title, options)
wfProfileIn("Parser::preprocess")
self.clearState
self.setOutputType(OT_PREPROCESS)
@mOptions = options
@mTitle = title
wfRunHooks("ParserBeforeStrip", [self, text, @mStripState])
text = self.strip(text, @mStripState)
wfRunHooks("ParserAfterStrip", [self, text, @mStripState])
text = Sanitizer.removeHTMLcomments(text) if @mOptions.getRemoveComments
text = self.replaceVariables(text)
text = @mStripState.unstripBoth(text)
wfProfileOut("Parser::preprocess")
return text
end
def getRandomString
return (dechex(mt_rand(0, 2147483647)) + dechex(mt_rand(0, 2147483647)))
end
def getTitle
return @mTitle
end
def getOptions
return @mOptions
end
def getFunctionLang
(php_global(:wgLang)
php_global(:wgContLang))
return @mOptions.getInterfaceMessage ? (wgLang) : (wgContLang)
end
def extractTagsAndParams(elements, text, matches, uniq_prefix = "")
php_static_var(:static => (true))
stripped = ""
matches = []
taglist = implode("|", elements)
start = ("/<(" + (taglist + ")(\\s+[^>]*?|\\s*?)(\\/?>)|<(!--)/i"))
while (not ("" == text)) do
p = preg_split(start, text, 2, PREG_SPLIT_DELIM_CAPTURE)
stripped = (stripped + p[0])
break if (count(p) < 5)
if (count(p) > 5) then
element = p[4]
attributes = ""
close = ""
inside = p[5]
else
element = p[1]
attributes = p[2]
close = p[3]
inside = p[4]
end
marker = ("" + (uniq_prefix + ("-" + (element + ("-" + (sprintf("%08X", n = (n + 1)) + "-QINU"))))))
stripped = (stripped + marker)
if (close == "/>") then
content = nil
text = inside
tail = nil
else
if (element == "!--") then
_end = "/(-->)/"
else
_end = ("/(<\\/" + (element + "\\s*>)/i"))
end
q = preg_split(_end, inside, 2, PREG_SPLIT_DELIM_CAPTURE)
content = q[0]
if (count(q) < 3) then
tail = ""
text = ""
else
tail = q[1]
text = q[2]
end
end
matches[marker] = [element, content, Sanitizer.decodeTagAttributes(attributes), ("<" + (element + (attributes + (close + (content + tail)))))]
end
return stripped
end
def strip(text, state, stripcomments = false, dontstrip = [])
php_global(:wgContLang)
wfProfileIn("Parser::strip")
render = (@mOutputType == OT_HTML)
uniq_prefix = @mUniqPrefix
commentState = ReplacementArray.new
nowikiItems = []
generalItems = []
elements = array_merge(["nowiki", "gallery"], array_keys(@mTagHooks))
php_global(:wgRawHtml)
(elements << "html") if wgRawHtml
(elements << "math") if @mOptions.getUseTeX
elements.each do |v|
next if (not in_array(v, dontstrip))
elements.delete(k)
end
matches = []
text = Parser.extractTagsAndParams(elements, text, matches, uniq_prefix)
matches.each do |data|
element, content, params, tag = *data
if render then
tagName = strtolower(element)
wfProfileIn(("Parser::strip-render-" + tagName))
case tagName
when "!--" then
if (substr(tag, -3) == "-->") then
output = tag
else
output = ("" + (tag + "-->"))
end
when "html" then
if wgRawHtml then
output = content
break
end
output = Xml.escapeTagsOnly(content)
when "nowiki" then
output = Xml.escapeTagsOnly(content)
when "math" then
output = wgContLang.armourMath(MathRenderer.renderMath(content))
when "gallery" then
output = self.renderImageGallery(content, params)
else
(if defined?(@mTagHooks[tagName]) then
output = call_user_func_array(@mTagHooks[tagName], [content, params, self])
else
raise(MWException.new(("Invalid call hook " + element)))
end)
end
wfProfileOut(("Parser::strip-render-" + tagName))
else
output = tag
end
output = state.unstripBoth(output)
if ((not stripcomments) and (element == "!--")) then
commentState.setPair(marker, output)
else
if ((element == "html") or (element == "nowiki")) then
nowikiItems[marker] = output
else
generalItems[marker] = output
end
end
end
state.nowiki.mergeArray(nowikiItems)
state.general.mergeArray(generalItems)
text = commentState.replace(text) if (not stripcomments)
wfProfileOut("Parser::strip")
return text
end
def unstrip(text, state)
return state.unstripGeneral(text)
end
def unstripNoWiki(text, state)
return state.unstripNoWiki(text)
end
def unstripForHTML(text)
return @mStripState.unstripBoth(text)
end
def insertStripItem(text, state)
rnd = (@mUniqPrefix + ("-item" + Parser.getRandomString))
state.general.setPair(rnd, text)
return rnd
end
def tidy(text)
php_global(:wgTidyInternal)
wrappedtext = ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html><head><title>test</title></head><body>" + (text + "</body></html>"))
if wgTidyInternal then
correctedtext = Parser.internalTidy(wrappedtext)
else
correctedtext = Parser.externalTidy(wrappedtext)
end
if is_null(correctedtext) then
wfDebug("Tidy error detected!\n")
return (text + "\n<!-- Tidy found serious XHTML errors -->\n")
end
return correctedtext
end
def externalTidy(text)
(php_global(:wgTidyConf)
php_global(:wgTidyBin)
php_global(:wgTidyOpts))
fname = "Parser::externalTidy"
wfProfileIn(fname)
cleansource = ""
opts = " -utf8"
descriptorspec = { 0 => (["pipe", "r"]), 1 => (["pipe", "w"]), 2 => (["file", "/dev/null", "a"]) }
pipes = []
process = proc_open(("" + (wgTidyBin + (" -config " + (wgTidyConf + (" " + (wgTidyOpts + opts)))))), descriptorspec, pipes)
if is_resource(process) then
fwrite(pipes[0], text)
fclose(pipes[0])
while (not feof(pipes[1])) do
cleansource = (cleansource + fgets(pipes[1], 1024))
end
fclose(pipes[1])
proc_close(process)
end
wfProfileOut(fname)
if ((cleansource == "") and (not (text == ""))) then
return nil
else
return cleansource
end
end
def internalTidy(text)
php_global(:wgTidyConf)
fname = "Parser::internalTidy"
wfProfileIn(fname)
tidy_load_config(wgTidyConf)
tidy_set_encoding("utf8")
tidy_parse_string(text)
tidy_clean_repair
if (tidy_get_status == 2) then
cleansource = nil
else
cleansource = tidy_get_output
end
wfProfileOut(fname)
return cleansource
end
def doTableStuff(text)
fname = "Parser::doTableStuff"
wfProfileIn(fname)
lines = explode("\n", text)
td_history = []
last_tag_history = []
tr_history = []
tr_attributes = []
has_opened_tr = []
indent_level = 0
lines.each do |line|
line = trim(line)
next if (line == "")
first_character = line[(0..0)]
matches = []
if preg_match("/^(:*)\\{\\|(.*)$/", line, matches) then
indent_level = strlen(matches[1])
attributes = @mStripState.unstripBoth(matches[2])
attributes = Sanitizer.fixTagAttributes(attributes, "table")
lines[key] = (str_repeat("<dl><dd>", indent_level) + ("<table" + (attributes + ">")))
array_push(td_history, false)
array_push(last_tag_history, "")
array_push(tr_history, false)
array_push(tr_attributes, "")
array_push(has_opened_tr, false)
else
if (count(td_history) == 0) then
next
else
if (substr(line, 0, 2) == "|}") then
line = ("</table>" + substr(line, 2))
last_tag = array_pop(last_tag_history)
line = ("<tr><td></td></tr>" + line) if (not array_pop(has_opened_tr))
line = ("</tr>" + line) if array_pop(tr_history)
line = ("</" + (last_tag + (">" + line))) if array_pop(td_history)
array_pop(tr_attributes)
lines[key] = (line + str_repeat("</dd></dl>", indent_level))
else
if (substr(line, 0, 2) == "|-") then
line = preg_replace("#^\\|-+#", "", line)
attributes = @mStripState.unstripBoth(line)
attributes = Sanitizer.fixTagAttributes(attributes, "tr")
array_pop(tr_attributes)
array_push(tr_attributes, attributes)
line = ""
last_tag = array_pop(last_tag_history)
array_pop(has_opened_tr)
array_push(has_opened_tr, true)
line = "</tr>" if array_pop(tr_history)
line = ("</" + (last_tag + (">" + line))) if array_pop(td_history)
lines[key] = line
array_push(tr_history, false)
array_push(td_history, false)
array_push(last_tag_history, "")
else
if (((first_character == "|") or (first_character == "!")) or (substr(line, 0, 2) == "|+")) then
if (substr(line, 0, 2) == "|+") then
first_character = "+"
line = substr(line, 1)
end
line = substr(line, 1)
line = str_replace("!!", "||", line) if (first_character == "!")
cells = StringUtils.explodeMarkup("||", line)
lines[key] = ""
cells.each do |cell|
previous = ""
if (not (first_character == "+")) then
tr_after = array_pop(tr_attributes)
previous = ("<tr" + (tr_after + ">\n")) if (not array_pop(tr_history))
array_push(tr_history, true)
array_push(tr_attributes, "")
array_pop(has_opened_tr)
array_push(has_opened_tr, true)
end
last_tag = array_pop(last_tag_history)
previous = ("</" + (last_tag + (">" + previous))) if array_pop(td_history)
if (first_character == "|") then
last_tag = "td"
else
if (first_character == "!") then
last_tag = "th"
else
(first_character == "+") ? (last_tag = "caption") : (last_tag = "")
end
end
array_push(last_tag_history, last_tag)
cell_data = explode("|", cell, 2)
if (not (strpos(cell_data[0], "[[") == false)) then
cell = ("" + (previous + ("<" + (last_tag + (">" + cell)))))
else
if (count(cell_data) == 1) then
cell = ("" + (previous + ("<" + (last_tag + (">" + cell_data[0])))))
else
attributes = @mStripState.unstripBoth(cell_data[0])
attributes = Sanitizer.fixTagAttributes(attributes, last_tag)
cell = ("" + (previous + ("<" + (last_tag + (attributes + (">" + cell_data[1]))))))
end
end
lines[key] = (lines[key] + cell)
array_push(td_history, true)
end
end
end
end
end
end
end
while (count(td_history) > 0) do
(lines << "</td>") if array_pop(td_history)
(lines << "</tr>") if array_pop(tr_history)
(lines << "<tr><td></td></tr>") if (not array_pop(has_opened_tr))
(lines << "</table>")
end
output = implode("\n", lines)
output = "" if (output == "<table>\n<tr><td></td></tr>\n</table>")
wfProfileOut(fname)
return output
end
def internalParse(text)
args = []
isMain = true
fname = "Parser::internalParse"
wfProfileIn(fname)
if (not wfRunHooks("ParserBeforeInternalParse", [self, text, @mStripState])) then
wfProfileOut(fname)
return text
end
text = strtr(text, "<onlyinclude>" => "", "</onlyinclude>" => "")
text = strtr(text, "<noinclude>" => "", "</noinclude>" => "")
text = StringUtils.delimiterReplace("<includeonly>", "</includeonly>", "", text)
text = Sanitizer.removeHTMLtags(text, [self, "attributeStripCallback"])
text = self.replaceVariables(text, args)
wfRunHooks("InternalParseBeforeLinks", [self, text, @mStripState])
text = self.doTableStuff(text)
text = preg_replace("/(^|\\n)-----*/", "\\1<hr />", text)
text = self.stripToc(text)
self.stripNoGallery(text)
text = self.doHeadings(text)
if @mOptions.getUseDynamicDates then
df = DateFormatter.getInstance
text = df.reformat(@mOptions.getDateFormat, text)
end
text = self.doAllQuotes(text)
text = self.replaceInternalLinks(text)
text = self.replaceExternalLinks(text)
text = str_replace((@mUniqPrefix + "NOPARSE"), "", text)
text = self.doMagicLinks(text)
text = self.formatHeadings(text, isMain)
wfProfileOut(fname)
return text
end
def doMagicLinks(text)
wfProfileIn("Parser::doMagicLinks")
text = preg_replace_callback("!(?: # Start cases\n\t\t\t <a.*?</a> | # Skip link text\n\t\t\t <.*?> | # Skip stuff inside HTML elements\n\t\t\t (?:RFC|PMID)\\s+([0-9]+) | # RFC or PMID, capture number as m[1]\n\t\t\t ISBN\\s+(\\b # ISBN, capture number as m[2]\n (?: 97[89] [\\ \\-]? )? # optional 13-digit ISBN prefix\n (?: [0-9] [\\ \\-]? ){9} # 9 digits with opt. delimiters\n [0-9Xx] # check digit\n \\b)\n\t\t\t)!x", [self, "magicLinkCallback"], text)
wfProfileOut("Parser::doMagicLinks")
return text
end
def magicLinkCallback(m)
if (substr(m[0], 0, 1) == "<") then
return m[0]
else
if (substr(m[0], 0, 4) == "ISBN") then
isbn = m[2]
num = strtr(isbn, "-" => "", " " => "", "x" => "X")
titleObj = SpecialPage.getTitleFor("Booksources")
text = ("<a href=\"" + (titleObj.escapeLocalUrl(("isbn=" + num)) + ("\" class=\"internal\">ISBN " + (isbn + "</a>"))))
else
if (substr(m[0], 0, 3) == "RFC") then
keyword = "RFC"
urlmsg = "rfcurl"
id = m[1]
else
if (substr(m[0], 0, 4) == "PMID") then
keyword = "PMID"
urlmsg = "pubmedurl"
id = m[1]
else
raise(MWException.new(("Parser::magicLinkCallback: unrecognised match type \"" + (substr(m[0], 0, 20) + "\""))))
end
end
url = wfMsg(urlmsg, id)
sk = @mOptions.getSkin
la = sk.getExternalLinkAttributes(url, (keyword + id))
text = ("<a href=\"" + (url + ("\"" + (la + (">" + (keyword + (" " + (id + "</a>"))))))))
end
end
return text
end
def doHeadings(text)
fname = "Parser::doHeadings"
wfProfileIn(fname)
(i = 6
while (i >= 1) do
(h = str_repeat("=", i)
text = preg_replace(("/^" + (h + ("(.+)" + (h + "\\s*$/m")))), ("<h" + (i + (">\\1</h" + (i + ">\\2")))), text))
i = (i - 1)
end)
wfProfileOut(fname)
return text
end
def doAllQuotes(text)
fname = "Parser::doAllQuotes"
wfProfileIn(fname)
outtext = ""
lines = explode("\n", text)
lines.each { |line| outtext = (outtext + (self.doQuotes(line) + "\n")) }
outtext = substr(outtext, 0, -1)
wfProfileOut(fname)
return outtext
end
def doQuotes(text)
arr = preg_split("/(''+)/", text, -1, PREG_SPLIT_DELIM_CAPTURE)
if (count(arr) == 1) then
return text
else
i = 0
numbold = 0
numitalics = 0
arr.each do |r|
if ((i % 2) == 1) then
if (strlen(arr[i]) == 4) then
arr[(i - 1)] = (arr[(i - 1)] + "'")
arr[i] = "'''"
else
if (strlen(arr[i]) > 5) then
arr[(i - 1)] = (arr[(i - 1)] + str_repeat("'", (strlen(arr[i]) - 5)))
arr[i] = "'''''"
end
end
if (strlen(arr[i]) == 2) then
numitalics = (numitalics + 1)
else
if (strlen(arr[i]) == 3) then
numbold = (numbold + 1)
else
if (strlen(arr[i]) == 5) then
numitalics = (numitalics + 1)
numbold = (numbold + 1)
end
end
end
end
i = (i + 1)
end
if (((numbold % 2) == 1) and ((numitalics % 2) == 1)) then
i = 0
firstsingleletterword = -1
firstmultiletterword = -1
firstspace = -1
arr.each do |r|
if (((i % 2) == 1) and (strlen(r) == 3)) then
x1 = substr(arr[(i - 1)], -1)
x2 = substr(arr[(i - 1)], -2, 1)
if (x1 == " ") then
firstspace = i if (firstspace == -1)
else
if (x2 == " ") then
firstsingleletterword = i if (firstsingleletterword == -1)
else
firstmultiletterword = i if (firstmultiletterword == -1)
end
end
end
i = (i + 1)
end
if (firstsingleletterword > -1) then
arr[firstsingleletterword] = "''"
arr[(firstsingleletterword - 1)] = (arr[(firstsingleletterword - 1)] + "'")
else
if (firstmultiletterword > -1) then
arr[firstmultiletterword] = "''"
arr[(firstmultiletterword - 1)] = (arr[(firstmultiletterword - 1)] + "'")
else
if (firstspace > -1) then
arr[firstspace] = "''"
arr[(firstspace - 1)] = (arr[(firstspace - 1)] + "'")
end
end
end
end
output = ""
buffer = ""
state = ""
i = 0
arr.each do |r|
if ((i % 2) == 0) then
(state == "both") ? (buffer = (buffer + r)) : (output = (output + r))
else
if (strlen(r) == 2) then
if (state == "i") then
output = (output + "</i>")
state = ""
else
if (state == "bi") then
output = (output + "</i>")
state = "b"
else
if (state == "ib") then
output = (output + "</b></i><b>")
state = "b"
else
if (state == "both") then
output = (output + ("<b><i>" + (buffer + "</i>")))
state = "b"
else
output = (output + "<i>")
state = (state + "i")
end
end
end
end
else
if (strlen(r) == 3) then
if (state == "b") then
output = (output + "</b>")
state = ""
else
if (state == "bi") then
output = (output + "</i></b><i>")
state = "i"
else
if (state == "ib") then
output = (output + "</b>")
state = "i"
else
if (state == "both") then
output = (output + ("<i><b>" + (buffer + "</b>")))
state = "i"
else
output = (output + "<b>")
state = (state + "b")
end
end
end
end
else
if (strlen(r) == 5) then
if (state == "b") then
output = (output + "</b><i>")
state = "i"
else
if (state == "i") then
output = (output + "</i><b>")
state = "b"
else
if (state == "bi") then
output = (output + "</i></b>")
state = ""
else
if (state == "ib") then
output = (output + "</b></i>")
state = ""
else
if (state == "both") then
output = (output + ("<i><b>" + (buffer + "</b></i>")))
state = ""
else
buffer = ""
state = "both"
end
end
end
end
end
end
end
end
end
i = (i + 1)
end
output = (output + "</b>") if ((state == "b") or (state == "ib"))
if (((state == "i") or (state == "bi")) or (state == "ib")) then
output = (output + "</i>")
end
output = (output + "</b>") if (state == "bi")
if ((state == "both") and buffer) then
output = (output + ("<b><i>" + (buffer + "</i></b>")))
end
return output
end
end
def replaceExternalLinks(text)
php_global(:wgContLang)
fname = "Parser::replaceExternalLinks"
wfProfileIn(fname)
sk = @mOptions.getSkin
bits = preg_split(EXT_LINK_BRACKETED, text, -1, PREG_SPLIT_DELIM_CAPTURE)
s = self.replaceFreeExternalLinks(array_shift(bits))
i = 0
while (i < count(bits)) do
url = bits[i = (i + 1)]
protocol = bits[i = (i + 1)]
text = bits[i = (i + 1)]
trail = bits[i = (i + 1)]
m2 = []
if preg_match("/&(lt|gt);/", url, m2, PREG_OFFSET_CAPTURE) then
text = (substr(url, m2[0][1]) + (" " + text))
url = substr(url, 0, m2[0][1])
end
img = self.maybeMakeExternalImage(text)
text = img if (not (img == false))
dtrail = ""
linktype = (text == url) ? ("free") : ("text")
if (text == "") then
if (not (strpos(wfUrlProtocols, substr(protocol, 0, strpos(protocol, ":"))) == false)) then
text = ("[" + ((@mAutonumber = (@mAutonumber + 1)) + "]"))
linktype = "autonumber"
else
text = htmlspecialchars(url)
linktype = "free"
end
else
dtrail, trail = *Linker.splitTrail(trail)
end
text = wgContLang.markNoConversion(text)
url = Sanitizer.cleanUrl(url)
trail = self.replaceFreeExternalLinks(trail)
s = (s + (sk.makeExternalLink(url, text, false, linktype, @mTitle.getNamespace) + (dtrail + trail)))
pasteurized = Parser.replaceUnusualEscapes(url)
@mOutput.addExternalLink(pasteurized)
end
wfProfileOut(fname)
return s
end
def replaceFreeExternalLinks(text)
php_global(:wgContLang)
fname = "Parser::replaceFreeExternalLinks"
wfProfileIn(fname)
bits = preg_split(("/(\\b(?:" + (wfUrlProtocols + "))/S")), text, -1, PREG_SPLIT_DELIM_CAPTURE)
s = array_shift(bits)
i = 0
sk = @mOptions.getSkin
while (i < count(bits)) do
protocol = bits[i = (i + 1)]
remainder = bits[i = (i + 1)]
m = []
if preg_match(("/^(" + (EXT_LINK_URL_CLASS + "+)(.*)$/s")), remainder, m) then
url = (protocol + m[1])
trail = m[2]
if ((((strlen(trail) == 0) and defined?(bits[i])) and preg_match(("/^" + (wfUrlProtocols + "$/S")), bits[i])) and preg_match(("/^(" + (EXT_LINK_URL_CLASS + "+)(.*)$/s")), bits[(i + 1)], m)) then
url = (url + (bits[i] + m[1]))
i = (i + 2)
trail = m[2]
end
m2 = []
if preg_match("/&(lt|gt);/", url, m2, PREG_OFFSET_CAPTURE) then
trail = (substr(url, m2[0][1]) + trail)
url = substr(url, 0, m2[0][1])
end
sep = ",;\\.:!?"
sep = (sep + ")") if (strpos(url, "(") == false)
numSepChars = strspn(strrev(url), sep)
if numSepChars then
trail = (substr(url, -numSepChars) + trail)
url = substr(url, 0, -numSepChars)
end
url = Sanitizer.cleanUrl(url)
text = self.maybeMakeExternalImage(url)
if (text == false) then
text = sk.makeExternalLink(url, wgContLang.markNoConversion(url), true, "free", @mTitle.getNamespace)
pasteurized = Parser.replaceUnusualEscapes(url)
@mOutput.addExternalLink(pasteurized)
else
pasteurized = Parser.replaceUnusualEscapes(url)
@mOutput.addExternalLink(pasteurized)
end
s = (s + (text + trail))
else
s = (s + (protocol + remainder))
end
end
wfProfileOut(fname)
return s
end
def replaceUnusualEscapes(url)
return preg_replace_callback("/%[0-9A-Fa-f]{2}/", ["Parser", "replaceUnusualEscapesCallback"], url)
end
def replaceUnusualEscapesCallback(matches)
char = urldecode(matches[0])
ord = ord(char)
if (((ord > 32) and (ord < 127)) and (strpos("<>\"\#{}|\\^~[]`;/?", char) == false)) then
return char
else
return matches[0]
end
end
def maybeMakeExternalImage(url)
sk = @mOptions.getSkin
imagesfrom = @mOptions.getAllowExternalImagesFrom
imagesexception = (not empty(imagesfrom))
text = false
if (@mOptions.getAllowExternalImages or (imagesexception and (strpos(url, imagesfrom) == 0))) then
if preg_match(EXT_IMAGE_REGEX, url) then
text = sk.makeExternalImage(htmlspecialchars(url))
end
end
return text
end
def replaceInternalLinks(s)
php_global(:wgContLang)
php_static_var(:static => (true))
wfProfileIn(fname)
wfProfileIn((fname + "-setup"))
php_static_var(:static => (true))
tc = (Title.legalChars + "#%") if (not tc)
sk = @mOptions.getSkin
a = explode("[[", (" " + s))
s = array_shift(a)
s = substr(s, 1)
php_static_var(:static => (true))
e1 = ("/^([" + (tc + "]+)(?:\\|(.+?))?]](.*)$/sD")) if (not e1)
php_static_var(:static => (true))
e1_img = ("/^([" + (tc + "]+)\\|(.*)$/sD")) if (not e1_img)
e2 = wfMsgForContent("linkprefix")
useLinkPrefixExtension = wgContLang.linkPrefixExtension
if is_null(@mTitle) then
raise(MWException.new("Parser::replaceInternalLinks: $this->mTitle is null\n"))
end
nottalk = (not @mTitle.isTalkPage)
if useLinkPrefixExtension then
m = []
preg_match(e2, s, m) ? (first_prefix = m[2]) : (first_prefix = false)
else
prefix = ""
end
if wgContLang.hasVariants then
selflink = wgContLang.convertLinkToAllVariants(@mTitle.getPrefixedText)
else
selflink = [@mTitle.getPrefixedText]
end
useSubpages = self.areSubpagesAllowed
wfProfileOut((fname + "-setup"))
(k = 0
while defined?(a[k]) do
(line = a[k]
if useLinkPrefixExtension then
wfProfileIn((fname + "-prefixhandling"))
if preg_match(e2, s, m) then
prefix = m[2]
s = m[1]
else
prefix = ""
end
if first_prefix then
prefix = first_prefix
first_prefix = false
end
wfProfileOut((fname + "-prefixhandling"))
end
might_be_img = false
wfProfileIn(("" + (fname + "-e1")))
if preg_match(e1, line, m) then
text = m[2]
if (((not (text == "")) and (substr(m[3], 0, 1) == "]")) and (not (strpos(text, "[") == false))) then
text = (text + "]")
m[3] = substr(m[3], 1)
end
if (not (strpos(m[1], "%") == false)) then
m[1] = str_replace(["<", ">"], ["&lt;", "&gt;"], urldecode(m[1]))
end
trail = m[3]
else
if preg_match(e1_img, line, m) then
might_be_img = true
text = m[2]
m[1] = urldecode(m[1]) if (not (strpos(m[1], "%") == false))
trail = ""
else
s = (s + (prefix + ("[[" + line)))
wfProfileOut(("" + (fname + "-e1")))
next
end
end
wfProfileOut(("" + (fname + "-e1")))
wfProfileIn(("" + (fname + "-misc")))
if preg_match(("/^\\b(?:" + (wfUrlProtocols + ")/")), m[1]) then
s = (s + (prefix + ("[[" + line)))
next
end
useSubpages ? (link = self.maybeDoSubpageLink(m[1], text)) : (link = m[1])
noforce = (not (substr(m[1], 0, 1) == ":"))
link = substr(link, 1) if (not noforce)
wfProfileOut(("" + (fname + "-misc")))
wfProfileIn(("" + (fname + "-title")))
nt = Title.newFromText(@mStripState.unstripNoWiki(link))
if (not nt) then
s = (s + (prefix + ("[[" + line)))
wfProfileOut(("" + (fname + "-title")))
next
end
ns = nt.getNamespace
iw = nt.getInterWiki
wfProfileOut(("" + (fname + "-title")))
if might_be_img then
wfProfileIn(("" + (fname + "-might_be_img")))
if ((ns == NS_IMAGE) and noforce) then
found = false
while defined?(a[(k + 1)]) do
spliced = array_splice(a, (k + 1), 1)
next_line = array_shift(spliced)
m = explode("]]", next_line, 3)
if (count(m) == 3) then
found = true
text = (text + ("[[" + (m[0] + ("]]" + m[1]))))
trail = m[2]
break
else
if (count(m) == 2) then
text = (text + ("[[" + (m[0] + ("]]" + m[1]))))
else
text = (text + ("[[" + next_line))
break
end
end
end
if (not found) then
text = self.replaceInternalLinks(text)
s = (s + ("" + (prefix + ("[[" + (link + ("|" + text))))))
wfProfileOut(("" + (fname + "-might_be_img")))
next
end
else
s = (s + ("" + (prefix + ("[[" + (link + ("|" + text))))))
wfProfileOut(("" + (fname + "-might_be_img")))
next
end
wfProfileOut(("" + (fname + "-might_be_img")))
end
wasblank = ("" == text)
text = link if wasblank
if noforce then
wfProfileIn(("" + (fname + "-interwiki")))
if (((iw and @mOptions.getInterwikiMagic) and nottalk) and wgContLang.getLanguageName(iw)) then
@mOutput.addLanguageLink(nt.getFullText)
s = rtrim((s + prefix))
s = (s + (trim(trail, "\n") == "") ? ("") : ((prefix + trail)))
wfProfileOut(("" + (fname + "-interwiki")))
next
end
wfProfileOut(("" + (fname + "-interwiki")))
if (ns == NS_IMAGE) then
wfProfileIn(("" + (fname + "-image")))
if (not wfIsBadImage(nt.getDBkey, @mTitle)) then
text = self.replaceExternalLinks(text)
text = self.replaceInternalLinks(text)
s = (s + (prefix + (self.armorLinks(self.makeImage(nt, text)) + trail)))
@mOutput.addImage(nt.getDBkey)
wfProfileOut(("" + (fname + "-image")))
next
else
@mOutput.addImage(nt.getDBkey)
end
wfProfileOut(("" + (fname + "-image")))
end
if (ns == NS_CATEGORY) then
wfProfileIn(("" + (fname + "-category")))
s = rtrim((s + "\n"))
wasblank ? (sortkey = self.getDefaultSort) : (sortkey = text)
sortkey = Sanitizer.decodeCharReferences(sortkey)
sortkey = str_replace("\n", "", sortkey)
sortkey = wgContLang.convertCategoryKey(sortkey)
@mOutput.addCategory(nt.getDBkey, sortkey)
s = (s + (trim((prefix + trail), "\n") == "") ? ("") : ((prefix + trail)))
wfProfileOut(("" + (fname + "-category")))
next
end
end
if (nt.getFragment == "") then
if in_array(nt.getPrefixedText, selflink, true) then
s = (s + (prefix + sk.makeSelfLinkObj(nt, text, "", trail)))
next
end
end
if (ns == NS_MEDIA) then
link = sk.makeMediaLinkObj(nt, text)
s = (s + (prefix + (self.armorLinks(link) + trail)))
@mOutput.addImage(nt.getDBkey)
next
else
if (ns == NS_SPECIAL) then
s = (s + self.makeKnownLinkHolder(nt, text, "", trail, prefix))
next
else
if (ns == NS_IMAGE) then
img = Image.new(nt)
if img.exists then
s = (s + self.makeKnownLinkHolder(nt, text, "", trail, prefix))
@mOutput.addLink(nt)
next
end
end
end
end
s = (s + self.makeLinkHolder(nt, text, "", trail, prefix)))
k = (k + 1)
end)
wfProfileOut(fname)
return s
end
def makeLinkHolder(nt, text = "", query = "", trail = "", prefix = "")
wfProfileIn("Parser::makeLinkHolder")
if (not is_object(nt)) then
retVal = ("<!-- ERROR -->" + (prefix + (text + trail)))
else
inside, trail = *Linker.splitTrail(trail)
if nt.isExternal then
nr = array_push(@mInterwikiLinkHolders["texts"], (prefix + (text + inside)))
(@mInterwikiLinkHolders["titles"] << nt)
retVal = ("<!--IWLINK " + ((nr - 1) + ("-->" + trail)))
else
nr = array_push(@mLinkHolders["namespaces"], nt.getNamespace)
(@mLinkHolders["dbkeys"] << nt.getDBkey)
(@mLinkHolders["queries"] << query)
(@mLinkHolders["texts"] << (prefix + (text + inside)))
(@mLinkHolders["titles"] << nt)
retVal = ("<!--LINK " + ((nr - 1) + ("-->" + trail)))
end
end
wfProfileOut("Parser::makeLinkHolder")
return retVal
end
def makeKnownLinkHolder(nt, text = "", query = "", trail = "", prefix = "")
inside, trail = *Linker.splitTrail(trail)
sk = @mOptions.getSkin
link = sk.makeKnownLinkObj(nt, text, query, inside, prefix)
return (self.armorLinks(link) + trail)
end
def armorLinks(text)
return preg_replace(("/\\b(" + (wfUrlProtocols + ")/")), ("" + (@mUniqPrefix + "NOPARSE$1")), text)
end
def areSubpagesAllowed
php_global(:wgNamespacesWithSubpages)
return (not empty(wgNamespacesWithSubpages[@mTitle.getNamespace]))
end
def maybeDoSubpageLink(target, text)
fname = "Parser::maybeDoSubpageLink"
wfProfileIn(fname)
ret = target
target = trim(target)
if self.areSubpagesAllowed then
if ((not (target == "")) and (target[(0..0)] == "/")) then
trailingSlashes = preg_match_all("%(/+)$%", target, m)
if trailingSlashes then
noslash = target = substr(target, 1, -strlen(m[0][0]))
else
noslash = substr(target, 1)
end
ret = (@mTitle.getPrefixedText + ("/" + trim(noslash)))
text = target if ("" == text)
else
dotdotcount = 0
nodotdot = target
while (strncmp(nodotdot, "../", 3) == 0) do
dotdotcount = (dotdotcount + 1)
nodotdot = substr(nodotdot, 3)
end
if (dotdotcount > 0) then
exploded = explode("/", @mTitle.GetPrefixedText)
if (count(exploded) > dotdotcount) then
ret = implode("/", array_slice(exploded, 0, -dotdotcount))
if (substr(nodotdot, -1, 1) == "/") then
nodotdot = substr(nodotdot, 0, -1)
text = nodotdot if ("" == text)
end
nodotdot = trim(nodotdot)
ret = (ret + ("/" + nodotdot)) if (not (nodotdot == ""))
end
end
end
end
wfProfileOut(fname)
return ret
end
def closeParagraph
result = ""
result = ("</" + (@mLastSection + ">\n")) if (not ("" == @mLastSection))
@mInPre = false
@mLastSection = ""
return result
end
def getCommon(st1, st2)
fl = strlen(st1)
shorter = strlen(st2)
shorter = fl if (fl < shorter)
(i = 0
while (i < shorter) do
break if (not (st1[(i..i)] == st2[(i..i)]))
i = (i + 1)
end)
return i
end
def openList(char)
result = self.closeParagraph
if ("*" == char) then
result = (result + "<ul><li>")
else
if ("#" == char) then
result = (result + "<ol><li>")
else
if (":" == char) then
result = (result + "<dl><dd>")
else
if (";" == char) then
result = (result + "<dl><dt>")
@mDTopen = true
else
result = "<!-- ERR 1 -->"
end
end
end
end
return result
end
def nextItem(char)
if (("*" == char) or ("#" == char)) then
return "</li><li>"
else
if ((":" == char) or (";" == char)) then
close = "</dd>"
close = "</dt>" if @mDTopen
if (";" == char) then
@mDTopen = true
return (close + "<dt>")
else
@mDTopen = false
return (close + "<dd>")
end
end
end
return "<!-- ERR 2 -->"
end
def closeList(char)
if ("*" == char) then
text = "</li></ul>"
else
if ("#" == char) then
text = "</li></ol>"
else
if (":" == char) then
if @mDTopen then
@mDTopen = false
text = "</dt></dl>"
else
text = "</dd></dl>"
end
else
return "<!-- ERR 3 -->"
end
end
end
return (text + "\n")
end
def doBlockLevels(text, linestart)
fname = "Parser::doBlockLevels"
wfProfileIn(fname)
textLines = explode("\n", text)
lastPrefix = output = ""
@mDTopen = inBlockElem = false
prefixLength = 0
paragraphStack = false
output = (output + array_shift(textLines)) if (not linestart)
textLines.each do |oLine|
lastPrefixLength = strlen(lastPrefix)
preCloseMatch = preg_match("/<\\/pre/i", oLine)
preOpenMatch = preg_match("/<pre/i", oLine)
if (not @mInPre) then
prefixLength = strspn(oLine, "*#:;")
pref = substr(oLine, 0, prefixLength)
pref2 = str_replace(";", ":", pref)
t = substr(oLine, prefixLength)
@mInPre = (not empty(preOpenMatch))
else
prefixLength = 0
pref = pref2 = ""
t = oLine
end
if (prefixLength and (0 == strcmp(lastPrefix, pref2))) then
output = (output + self.nextItem(substr(pref, -1)))
paragraphStack = false
if (substr(pref, -1) == ";") then
term = t2 = ""
if (not (self.findColonNoLinks(t, term, t2) == false)) then
t = t2
output = (output + (term + self.nextItem(":")))
end
end
else
if (prefixLength or lastPrefixLength) then
commonPrefixLength = self.getCommon(pref, lastPrefix)
paragraphStack = false
while (commonPrefixLength < lastPrefixLength) do
output = (output + self.closeList(lastPrefix[((lastPrefixLength - 1)..(lastPrefixLength - 1))]))
lastPrefixLength = (lastPrefixLength - 1)
end
if ((prefixLength <= commonPrefixLength) and (commonPrefixLength > 0)) then
output = (output + self.nextItem(pref[((commonPrefixLength - 1)..(commonPrefixLength - 1))]))
end
while (prefixLength > commonPrefixLength) do
char = substr(pref, commonPrefixLength, 1)
output = (output + self.openList(char))
if (";" == char) then
if (not (self.findColonNoLinks(t, term, t2) == false)) then
t = t2
output = (output + (term + self.nextItem(":")))
end
end
commonPrefixLength = (commonPrefixLength + 1)
end
lastPrefix = pref2
end
end
if (0 == prefixLength) then
wfProfileIn(("" + (fname + "-paragraph")))
openmatch = preg_match("/(?:<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|<p|<ul|<ol|<li|<\\/tr|<\\/td|<\\/th)/iS", t)
closematch = preg_match(("/(?:<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|<td|<th|<\\/?div|<hr|<\\/pre|<\\/p|" + (@mUniqPrefix + "-pre|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS")), t)
if (openmatch or closematch) then
paragraphStack = false
output = (output + self.closeParagraph)
@mInPre = true if (preOpenMatch and (not preCloseMatch))
closematch ? (inBlockElem = false) : (inBlockElem = true)
else
if ((not inBlockElem) and (not @mInPre)) then
if ((" " == t[(0..0)]) and ((@mLastSection == "pre") or (not (trim(t) == "")))) then
if (not (@mLastSection == "pre")) then
paragraphStack = false
output = (output + (self.closeParagraph + "<pre>"))
@mLastSection = "pre"
end
t = substr(t, 1)
else
if ("" == trim(t)) then
if paragraphStack then
output = (output + (paragraphStack + "<br />"))
paragraphStack = false
@mLastSection = "p"
else
if (not (@mLastSection == "p")) then
output = (output + self.closeParagraph)
@mLastSection = ""
paragraphStack = "<p>"
else
paragraphStack = "</p><p>"
end
end
else
if paragraphStack then
output = (output + paragraphStack)
paragraphStack = false
@mLastSection = "p"
else
if (not (@mLastSection == "p")) then
output = (output + (self.closeParagraph + "<p>"))
@mLastSection = "p"
end
end
end
end
end
end
wfProfileOut(("" + (fname + "-paragraph")))
end
@mInPre = false if (preCloseMatch and @mInPre)
output = (output + (t + "\n")) if (paragraphStack == false)
end
while prefixLength do
output = (output + self.closeList(pref2[((prefixLength - 1)..(prefixLength - 1))]))
prefixLength = (prefixLength - 1)
end
if (not ("" == @mLastSection)) then
output = (output + ("</" + (@mLastSection + ">")))
@mLastSection = ""
end
wfProfileOut(fname)
return output
end
def findColonNoLinks(str, before, after)
fname = "Parser::findColonNoLinks"
wfProfileIn(fname)
pos = strpos(str, ":")
if (pos == false) then
wfProfileOut(fname)
return false
end
lt = strpos(str, "<")
if ((lt == false) or (lt > pos)) then
before = substr(str, 0, pos)
after = substr(str, (pos + 1))
wfProfileOut(fname)
return pos
end
state = MW_COLON_STATE_TEXT
stack = 0
len = strlen(str)
(i = 0
while (i < len) do
(c = str[(i..i)]
case state
when 0 then
case c
when "<" then
state = MW_COLON_STATE_TAGSTART
when ":" then
if (stack == 0) then
before = substr(str, 0, i)
after = substr(str, (i + 1))
wfProfileOut(fname)
return i
end
else
(colon = strpos(str, ":", i)
if (colon == false) then
wfProfileOut(fname)
return false
end
lt = strpos(str, "<", i)
if (stack == 0) then
if ((lt == false) or (colon < lt)) then
before = substr(str, 0, colon)
after = substr(str, (colon + 1))
wfProfileOut(fname)
return i
end
end
Php2Rb.break(2) if (lt == false)
i = lt
state = MW_COLON_STATE_TAGSTART)
end
when 1 then
case c
when ">" then
stack = (stack + 1)
state = MW_COLON_STATE_TEXT
when "/" then
state = MW_COLON_STATE_TAGSLASH
else
# do nothing
end
when 2 then
case c
when "/" then
state = MW_COLON_STATE_CLOSETAG
when "!" then
state = MW_COLON_STATE_COMMENT
when ">" then
state = MW_COLON_STATE_TEXT
else
(state = MW_COLON_STATE_TAG)
end
when 3 then
if (c == ">") then
stack = (stack - 1)
if (stack < 0) then
wfDebug(("Invalid input in " + (fname + "; too many close tags\n")))
wfProfileOut(fname)
return false
end
state = MW_COLON_STATE_TEXT
end
when MW_COLON_STATE_TAGSLASH then
(c == ">") ? (state = MW_COLON_STATE_TEXT) : (state = MW_COLON_STATE_TAG)
when 5 then
state = MW_COLON_STATE_COMMENTDASH if (c == "-")
when MW_COLON_STATE_COMMENTDASH then
if (c == "-") then
state = MW_COLON_STATE_COMMENTDASHDASH
else
state = MW_COLON_STATE_COMMENT
end
when MW_COLON_STATE_COMMENTDASHDASH then
if (c == ">") then
state = MW_COLON_STATE_TEXT
else
state = MW_COLON_STATE_COMMENT
end
else
(raise(MWException.new(("State machine error in " + fname))))
end)
i = (i + 1)
end)
if (stack > 0) then
wfDebug(("Invalid input in " + (fname + ("; not enough close tags (stack " + (stack + (", state " + (state + ")\n")))))))
return false
end
wfProfileOut(fname)
return false
end
def getVariableValue(index)
(php_global(:wgContLang)
php_global(:wgSitename)
php_global(:wgServer)
php_global(:wgServerName)
php_global(:wgScriptPath))
php_static_var(:static => (true))
if wfRunHooks("ParserGetVariableValueVarCache", [self, varCache]) then
return varCache[index] if defined?(varCache[index])
end
ts = time
wfRunHooks("ParserGetVariableValueTs", [self, ts])
php_global(:wgLocaltimezone)
if defined?(wgLocaltimezone) then
oldtz = getenv("TZ")
putenv(("TZ=" + wgLocaltimezone))
end
localTimestamp = date("YmdHis", ts)
localMonth = date("m", ts)
localMonthName = date("n", ts)
localDay = date("j", ts)
localDay2 = date("d", ts)
localDayOfWeek = date("w", ts)
localWeek = date("W", ts)
localYear = date("Y", ts)
localHour = date("H", ts)
putenv(("TZ=" + oldtz)) if defined?(wgLocaltimezone)
case index
when "currentmonth" then
return varCache[index] = wgContLang.formatNum(date("m", ts))
when "currentmonthname" then
return varCache[index] = wgContLang.getMonthName(date("n", ts))
when "currentmonthnamegen" then
return varCache[index] = wgContLang.getMonthNameGen(date("n", ts))
when "currentmonthabbrev" then
return varCache[index] = wgContLang.getMonthAbbreviation(date("n", ts))
when "currentday" then
return varCache[index] = wgContLang.formatNum(date("j", ts))
when "currentday2" then
return varCache[index] = wgContLang.formatNum(date("d", ts))
when "localmonth" then
return varCache[index] = wgContLang.formatNum(localMonth)
when "localmonthname" then
return varCache[index] = wgContLang.getMonthName(localMonthName)
when "localmonthnamegen" then
return varCache[index] = wgContLang.getMonthNameGen(localMonthName)
when "localmonthabbrev" then
return varCache[index] = wgContLang.getMonthAbbreviation(localMonthName)
when "localday" then
return varCache[index] = wgContLang.formatNum(localDay)
when "localday2" then
return varCache[index] = wgContLang.formatNum(localDay2)
when "pagename" then
return @mTitle.getText
when "pagenamee" then
return @mTitle.getPartialURL
when "fullpagename" then
return @mTitle.getPrefixedText
when "fullpagenamee" then
return @mTitle.getPrefixedURL
when "subpagename" then
return @mTitle.getSubpageText
when "subpagenamee" then
return @mTitle.getSubpageUrlForm
when "basepagename" then
return @mTitle.getBaseText
when "basepagenamee" then
return wfUrlEncode(str_replace(" ", "_", @mTitle.getBaseText))
when "talkpagename" then
if @mTitle.canTalk then
talkPage = @mTitle.getTalkPage
return talkPage.getPrefixedText
else
return ""
end
if @mTitle.canTalk then
talkPage = @mTitle.getTalkPage
return talkPage.getPrefixedUrl
else
return ""
end
subjPage = @mTitle.getSubjectPage
return subjPage.getPrefixedText
when "talkpagenamee" then
if @mTitle.canTalk then
talkPage = @mTitle.getTalkPage
return talkPage.getPrefixedUrl
else
return ""
end
subjPage = @mTitle.getSubjectPage
return subjPage.getPrefixedText
when "subjectpagename" then
subjPage = @mTitle.getSubjectPage
return subjPage.getPrefixedText
when "subjectpagenamee" then
subjPage = @mTitle.getSubjectPage
return subjPage.getPrefixedUrl
when "revisionid" then
return @mRevisionId
when "revisionday" then
return intval(substr(self.getRevisionTimestamp, 6, 2))
when "revisionday2" then
return substr(self.getRevisionTimestamp, 6, 2)
when "revisionmonth" then
return intval(substr(self.getRevisionTimestamp, 4, 2))
when "revisionyear" then
return substr(self.getRevisionTimestamp, 0, 4)
when "revisiontimestamp" then
return self.getRevisionTimestamp
when "namespace" then
return str_replace("_", " ", wgContLang.getNsText(@mTitle.getNamespace))
when "namespacee" then
return wfUrlencode(wgContLang.getNsText(@mTitle.getNamespace))
when "talkspace" then
return @mTitle.canTalk ? (str_replace("_", " ", @mTitle.getTalkNsText)) : ("")
when "talkspacee" then
return @mTitle.canTalk ? (wfUrlencode(@mTitle.getTalkNsText)) : ("")
when "subjectspace" then
return @mTitle.getSubjectNsText
when "subjectspacee" then
return wfUrlencode(@mTitle.getSubjectNsText)
when "currentdayname" then
return varCache[index] = wgContLang.getWeekdayName((date("w", ts) + 1))
when "currentyear" then
return varCache[index] = wgContLang.formatNum(date("Y", ts), true)
when "currenttime" then
return varCache[index] = wgContLang.time(wfTimestamp(TS_MW, ts), false, false)
when "currenthour" then
return varCache[index] = wgContLang.formatNum(date("H", ts), true)
when "currentweek" then
return varCache[index] = wgContLang.formatNum(date("W", ts).to_i)
when "currentdow" then
return varCache[index] = wgContLang.formatNum(date("w", ts))
when "localdayname" then
return varCache[index] = wgContLang.getWeekdayName((localDayOfWeek + 1))
when "localyear" then
return varCache[index] = wgContLang.formatNum(localYear, true)
when "localtime" then
return varCache[index] = wgContLang.time(localTimestamp, false, false)
when "localhour" then
return varCache[index] = wgContLang.formatNum(localHour, true)
when "localweek" then
return varCache[index] = wgContLang.formatNum(localWeek.to_i)
when "localdow" then
return varCache[index] = wgContLang.formatNum(localDayOfWeek)
when "numberofarticles" then
return varCache[index] = wgContLang.formatNum(SiteStats.articles)
when "numberoffiles" then
return varCache[index] = wgContLang.formatNum(SiteStats.images)
when "numberofusers" then
return varCache[index] = wgContLang.formatNum(SiteStats.users)
when "numberofpages" then
return varCache[index] = wgContLang.formatNum(SiteStats.pages)
when "numberofadmins" then
return varCache[index] = wgContLang.formatNum(SiteStats.admins)
when "numberofedits" then
return varCache[index] = wgContLang.formatNum(SiteStats.edits)
when "currenttimestamp" then
return varCache[index] = wfTimestampNow
when "localtimestamp" then
return varCache[index] = localTimestamp
when "currentversion" then
return varCache[index] = SpecialVersion.getVersion
when "sitename" then
return wgSitename
when "server" then
return wgServer
when "servername" then
return wgServerName
when "scriptpath" then
return wgScriptPath
when "directionmark" then
return wgContLang.getDirMark
when "contentlanguage" then
php_global(:wgContLanguageCode)
return wgContLanguageCode
else
(ret = nil
if wfRunHooks("ParserGetVariableValueSwitch", [self, varCache, index, ret]) then
return ret
else
return nil
end)
end
end
def initialiseVariables
fname = "Parser::initialiseVariables"
wfProfileIn(fname)
variableIDs = MagicWord.getVariableIDs
@mVariables = []
variableIDs.each do |id|
mw = MagicWord.get(id)
mw.addToArray(@mVariables, id)
end
wfProfileOut(fname)
end
def replace_callback(text, callbacks)
wfProfileIn("Parser::replace_callback")
openingBraceStack = []
lastOpeningBrace = -1
validOpeningBraces = implode("", array_keys(callbacks))
i = 0
while (i < strlen(text)) do
if (lastOpeningBrace == -1) then
currentClosing = ""
search = validOpeningBraces
else
currentClosing = openingBraceStack[lastOpeningBrace]["braceEnd"]
search = (validOpeningBraces + ("|" + currentClosing))
end
rule = nil
i = (i + strcspn(text, search, i))
if (i < strlen(text)) then
if (text[i] == "|") then
found = "pipe"
else
if (text[i] == currentClosing) then
found = "close"
else
if defined?(callbacks[text[i]]) then
found = "open"
rule = callbacks[text[i]]
else
i = (i + 1)
next
end
end
end
else
break
end
if (found == "open") then
piece = { "brace" => (text[i]), "braceEnd" => (rule["end"]), "title" => "", "parts" => (nil) }
piece["count"] = strspn(text, piece["brace"], i)
piece["startAt"] = piece["partStart"] = (i + piece["count"])
i = (i + piece["count"])
if (piece["count"] >= rule["min"]) then
lastOpeningBrace = (lastOpeningBrace + 1)
openingBraceStack[lastOpeningBrace] = piece
end
else
if (found == "close") then
maxCount = openingBraceStack[lastOpeningBrace]["count"]
count = strspn(text, text[i], i, maxCount)
matchingCount = 0
matchingCallback = nil
cbType = callbacks[openingBraceStack[lastOpeningBrace]["brace"]]
if (count > cbType["max"]) then
matchingCount = cbType["max"]
else
matchingCount = count
while ((matchingCount > 0) and (not array_key_exists(matchingCount, cbType["cb"]))) do
matchingCount = (matchingCount - 1)
end
end
if (matchingCount <= 0) then
i = (i + count)
next
end
matchingCallback = cbType["cb"][matchingCount]
if (nil == openingBraceStack[lastOpeningBrace]["parts"]) then
openingBraceStack[lastOpeningBrace]["title"] = substr(text, openingBraceStack[lastOpeningBrace]["partStart"], (i - openingBraceStack[lastOpeningBrace]["partStart"]))
else
(openingBraceStack[lastOpeningBrace]["parts"] << substr(text, openingBraceStack[lastOpeningBrace]["partStart"], (i - openingBraceStack[lastOpeningBrace]["partStart"])))
end
pieceStart = (openingBraceStack[lastOpeningBrace]["startAt"] - matchingCount)
pieceEnd = (i + matchingCount)
if is_callable(matchingCallback) then
cbArgs = { "text" => (substr(text, pieceStart, (pieceEnd - pieceStart))), "title" => (trim(openingBraceStack[lastOpeningBrace]["title"])), "parts" => (openingBraceStack[lastOpeningBrace]["parts"]), "lineStart" => (((pieceStart > 0) and (text[(pieceStart - 1)] == "\n"))) }
replaceWith = call_user_func(matchingCallback, cbArgs)
text = (substr(text, 0, pieceStart) + (replaceWith + substr(text, pieceEnd)))
i = (pieceStart + strlen(replaceWith))
else
i = (i + matchingCount)
end
piece = { "brace" => (openingBraceStack[lastOpeningBrace]["brace"]), "braceEnd" => (openingBraceStack[lastOpeningBrace]["braceEnd"]), "count" => (openingBraceStack[lastOpeningBrace]["count"]), "title" => "", "parts" => (nil), "startAt" => (openingBraceStack[lastOpeningBrace]["startAt"]) }
openingBraceStack[lastOpeningBrace = (lastOpeningBrace - 1)] = nil
if (matchingCount < piece["count"]) then
piece["count"] = (piece["count"] - matchingCount)
piece["startAt"] = (piece["startAt"] - matchingCount)
piece["partStart"] = piece["startAt"]
currentCbList = callbacks[piece["brace"]]["cb"]
while piece["count"] do
if array_key_exists(piece["count"], currentCbList) then
lastOpeningBrace = (lastOpeningBrace + 1)
openingBraceStack[lastOpeningBrace] = piece
break
end
piece["count"] -= 1
end
end
else
if (found == "pipe") then
if (nil == openingBraceStack[lastOpeningBrace]["parts"]) then
openingBraceStack[lastOpeningBrace]["title"] = substr(text, openingBraceStack[lastOpeningBrace]["partStart"], (i - openingBraceStack[lastOpeningBrace]["partStart"]))
openingBraceStack[lastOpeningBrace]["parts"] = []
else
(openingBraceStack[lastOpeningBrace]["parts"] << substr(text, openingBraceStack[lastOpeningBrace]["partStart"], (i - openingBraceStack[lastOpeningBrace]["partStart"])))
end
openingBraceStack[lastOpeningBrace]["partStart"] = i = (i + 1)
end
end
end
end
wfProfileOut("Parser::replace_callback")
return text
end
def replaceVariables(text, args = [], argsOnly = false)
return text if (strlen(text) > @mOptions.getMaxIncludeSize)
fname = "Parser::replaceVariables"
wfProfileIn(fname)
array_push(@mArgStack, args)
braceCallbacks = []
braceCallbacks[2] = [self, "braceSubstitution"] if (not argsOnly)
if (not (@mOutputType == OT_MSG)) then
braceCallbacks[3] = [self, "argSubstitution"]
end
if braceCallbacks then
callbacks = { "{" => ({ "end" => "}", "cb" => (braceCallbacks), "min" => (argsOnly ? (3) : (2)), "max" => (defined?(braceCallbacks[3]) ? (3) : (2)) }), "[" => ({ "end" => "]", "cb" => ({ 2 => (nil) }), "min" => 2, "max" => 2 }) }
text = self.replace_callback(text, callbacks)
array_pop(@mArgStack)
end
wfProfileOut(fname)
return text
end
def variableSubstitution(matches)
php_global(:wgContLang)
fname = "Parser::variableSubstitution"
varname = wgContLang.lc(matches[1])
wfProfileIn(fname)
skip = false
if (@mOutputType == OT_WIKI) then
mwSubst = MagicWord.get("subst")
skip = true if (not mwSubst.matchStartAndRemove(varname))
end
if ((not skip) and array_key_exists(varname, @mVariables)) then
id = @mVariables[varname]
mw = MagicWord.get(id)
if mw.match(matches[1]) then
text = self.getVariableValue(id)
@mOutput.mContainsOldMagic=(true)
else
text = matches[0]
end
else
text = matches[0]
end
wfProfileOut(fname)
return text
end
def createAssocArgs(args)
assocArgs = []
index = 1
args.each do |arg|
eqpos = strpos(arg, "=")
if (eqpos == false) then
assocArgs[index = (index + 1)] = arg
else
name = trim(substr(arg, 0, eqpos))
value = trim(substr(arg, (eqpos + 1)))
value = "" if (value == false)
assocArgs[name] = value if (not (name == false))
end
end
return assocArgs
end
def braceSubstitution(piece)
(php_global(:wgContLang)
php_global(:wgLang)
php_global(:wgAllowDisplayTitle)
php_global(:wgNonincludableNamespaces))
fname = "Parser::braceSubstitution"
wfProfileIn(fname)
wfProfileIn("Parser::braceSubstitution-setup")
found = false
nowiki = false
noparse = false
noargs = false
replaceHeadings = false
headingOffset = 0
isHTML = false
forceRawInterwiki = false
title = nil
linestart = ""
titleText = part1 = piece["title"]
if (nil == piece["parts"]) then
replaceWith = self.variableSubstitution([piece["text"], piece["title"]])
if (not (replaceWith == piece["text"])) then
text = replaceWith
found = true
noparse = true
noargs = true
end
end
args = (nil == piece["parts"]) ? ([]) : (piece["parts"])
wfProfileOut("Parser::braceSubstitution-setup")
wfProfileIn("Parser::braceSubstitution-modifiers")
if (not found) then
mwSubst = MagicWord.get("subst")
if mwSubst.matchStartAndRemove(part1).^(@ot["wiki"]) then
text = piece["text"]
found = true
noparse = true
noargs = true
end
end
if (not found) then
mwMsgnw = MagicWord.get("msgnw")
if mwMsgnw.matchStartAndRemove(part1) then
nowiki = true
else
mwMsg = MagicWord.get("msg")
mwMsg.matchStartAndRemove(part1)
end
mwRaw = MagicWord.get("raw")
forceRawInterwiki = true if mwRaw.matchStartAndRemove(part1)
end
wfProfileOut("Parser::braceSubstitution-modifiers")
lastPathLevel = @mTemplatePath
if (not found) then
wfProfileIn("Parser::braceSubstitution-pfunc")
colonPos = strpos(part1, ":")
if (not (colonPos == false)) then
function = substr(part1, 0, colonPos)
if defined?(@mFunctionSynonyms[1][function]) then
function = @mFunctionSynonyms[1][function]
else
function = strtolower(function)
if defined?(@mFunctionSynonyms[0][function]) then
function = @mFunctionSynonyms[0][function]
else
function = false
end
end
if function then
funcArgs = array_map("trim", args)
funcArgs = array_merge([self, trim(substr(part1, (colonPos + 1)))], funcArgs)
result = call_user_func_array(@mFunctionHooks[function], funcArgs)
found = true
if is_array(result) then
if defined?(result[0]) then
text = (linestart + result[0])
result.delete(0)
end
extract(result)
else
text = (linestart + result)
end
end
end
wfProfileOut("Parser::braceSubstitution-pfunc")
end
if ((not found) and defined?(@mTemplates[piece["title"]])) then
found = true
if defined?(@mTemplatePath[part1]) then
noparse = true
noargs = true
found = true
text = (linestart + ("[[" + (part1 + "]]<!-- WARNING: template loop detected -->")))
wfDebug(("Parser::braceSubstitution: template loop broken at '" + (part1 + "'\n")))
else
text = (linestart + @mTemplates[piece["title"]])
ns = NS_TEMPLATE
subpage = ""
part1 = self.maybeDoSubpageLink(part1, subpage)
ns = @mTitle.getNamespace if (not (subpage == ""))
title = Title.newFromText(part1, ns)
titleText = title.getPrefixedText
replaceHeadings = true
end
end
if (not found) then
wfProfileIn("Parser::braceSubstitution-loadtpl")
ns = NS_TEMPLATE
subpage = ""
part1 = self.maybeDoSubpageLink(part1, subpage)
ns = @mTitle.getNamespace if (not (subpage == ""))
title = Title.newFromText(part1, ns)
if (not is_null(title)) then
titleText = title.getPrefixedText
if (wgContLang.hasVariants and (title.getArticleID == 0)) then
wgContLang.findVariantLink(part1, title)
end
if (not title.isExternal) then
if (((title.getNamespace == NS_SPECIAL) and @mOptions.getAllowSpecialInclusion) and @ot["html"]) then
text = SpecialPage.capturePath(title)
if is_string(text) then
found = true
noparse = true
noargs = true
isHTML = true
self.disableCache
end
else
if (wgNonincludableNamespaces and in_array(title.getNamespace, wgNonincludableNamespaces)) then
found = false
wfDebug(("" + (fname + (": template inclusion denied for " + title.getPrefixedDBkey))))
else
articleContent = self.fetchTemplate(title)
if (not (articleContent == false)) then
found = true
text = articleContent
replaceHeadings = true
end
end
end
if ((not found) and (@ot["html"] or @ot["pre"])) then
text = ("[[:" + (titleText + "]]"))
found = true
end
else
if title.isTrans then
if (@ot["html"] and (not forceRawInterwiki)) then
text = self.interwikiTransclude(title, "render")
isHTML = true
noparse = true
else
text = self.interwikiTransclude(title, "raw")
replaceHeadings = true
end
found = true
end
end
if found then
@mTemplates[piece["title"]] = text unless isHTML
text = (linestart + text)
end
end
wfProfileOut("Parser::braceSubstitution-loadtpl")
end
if (found and (not self.incrementIncludeSize("pre-expand", strlen(text)))) then
text = (linestart + ("[[" + (titleText + "]]<!-- WARNING: template omitted, pre-expand include size too large -->")))
noparse = true
noargs = true
end
if ((nowiki and found) and (@ot["html"] or @ot["pre"])) then
text = wfEscapeWikiText(text)
else
if ((not @ot["msg"]) and found) then
if noargs then
assocArgs = []
else
assocArgs = self.class.createAssocArgs(args)
@mTemplatePath[part1] = 1
end
if (not noparse) then
if (in_string("<onlyinclude>", text) and in_string("</onlyinclude>", text)) then
replacer = OnlyIncludeReplacer.new
StringUtils.delimiterReplaceCallback("<onlyinclude>", "</onlyinclude>", [replacer, "replace"], text)
text = replacer.output
end
text = StringUtils.delimiterReplace("<noinclude>", "</noinclude>", "", text)
text = strtr(text, "<includeonly>" => "", "</includeonly>" => "")
if (@ot["html"] or @ot["pre"]) then
text = self.strip(text, @mStripState)
if @ot["html"] then
text = Sanitizer.removeHTMLtags(text, [self, "replaceVariables"], assocArgs)
else
if (@ot["pre"] and @mOptions.getRemoveComments) then
text = Sanitizer.removeHTMLcomments(text)
end
end
end
text = self.replaceVariables(text, assocArgs)
if ((not piece["lineStart"]) and preg_match("/^(?:{\\||:|;|#|\\*)/", text)) then
text = ("\n" + text)
end
else
text = self.replaceVariables(text, assocArgs, true) if (not noargs)
end
end
end
@mTemplatePath = lastPathLevel
if (found and (not self.incrementIncludeSize("post-expand", strlen(text)))) then
text = (linestart + ("[[" + (titleText + "]]<!-- WARNING: template omitted, post-expand include size too large -->")))
noparse = true
noargs = true
end
if (not found) then
wfProfileOut(fname)
return piece["text"]
else
wfProfileIn("Parser::braceSubstitution-placeholders")
if isHTML then
text = ("\n\n" + self.insertStripItem(text, @mStripState))
else
if (((not @ot["wiki"]) and (not @ot["pre"])) and replaceHeadings) then
if (not is_null(title)) then
encodedname = base64_encode(title.getPrefixedDBkey)
else
encodedname = base64_encode("")
end
m = preg_split("/(^={1,6}.*?={1,6}\\s*?$)/m", text, -1, PREG_SPLIT_DELIM_CAPTURE)
text = ""
nsec = headingOffset
(i = 0
while (i < count(m)) do
(text = (text + m[i])
next if ((not defined?(m[(i + 1)])) or (m[(i + 1)] == ""))
hl = m[(i + 1)]
if strstr(hl, "<!--MWTEMPLATESECTION") then
text = (text + hl)
next
end
m2 = []
preg_match("/^(={1,6})(.*?)(={1,6})\\s*?$/m", hl, m2)
text = (text + (m2[1] + (m2[2] + ("<!--MWTEMPLATESECTION=" + (encodedname + ("&" + (base64_encode(("" + nsec)) + ("-->" + m2[3]))))))))
nsec = (nsec + 1))
i = (i + 2)
end)
end
end
wfProfileOut("Parser::braceSubstitution-placeholders")
end
@mTemplatePath = lastPathLevel
if (not found) then
wfProfileOut(fname)
return piece["text"]
else
wfProfileOut(fname)
return text
end
end
def fetchTemplate(title)
wfRunHooks("FixTemplateTitle", [title])
text = false
(i = 0
while ((i < 2) and is_object(title)) do
(rev = Revision.newFromTitle(title)
@mOutput.addTemplate(title, title.getArticleID)
if rev then
text = rev.getText
else
if (title.getNamespace == NS_MEDIAWIKI) then
php_global(:wgLang)
message = wgLang.lcfirst(title.getText)
text = wfMsgForContentNoTrans(message)
if wfEmptyMsg(message, text) then
text = false
break
end
else
break
end
end
break if (text == false)
title = Title.newFromRedirect(text))
i = (i + 1)
end)
return text
end
def interwikiTransclude(title, action)
php_global(:wgEnableScaryTranscluding)
return wfMsg("scarytranscludedisabled") if (not wgEnableScaryTranscluding)
url = title.getFullUrl(("action=" + action))
return wfMsg("scarytranscludetoolong") if (strlen(url) > 255)
return self.fetchScaryTemplateMaybeFromCache(url)
end
def fetchScaryTemplateMaybeFromCache(url)
php_global(:wgTranscludeCacheExpiry)
dbr = wfGetDB(DB_SLAVE)
obj = dbr.selectRow("transcache", ["tc_time", "tc_contents"], "tc_url" => (url))
if obj then
time = obj.tc_time
text = obj.tc_contents
return text if (time and (time < (time + wgTranscludeCacheExpiry)))
end
text = Http.get(url)
return wfMsg("scarytranscludefailed", url) if (not text)
dbw = wfGetDB(DB_MASTER)
dbw.replace("transcache", ["tc_url"], "tc_url" => (url), "tc_time" => (time), "tc_contents" => (text))
return text
end
def argSubstitution(matches)
arg = trim(matches["title"])
text = matches["text"]
inputArgs = end(@mArgStack)
if array_key_exists(arg, inputArgs) then
text = inputArgs[arg]
else
if ((((@mOutputType == OT_HTML) or (@mOutputType == OT_PREPROCESS)) and (not (nil == matches["parts"]))) and (count(matches["parts"]) > 0)) then
text = matches["parts"][0]
end
end
if (not self.incrementIncludeSize("arg", strlen(text))) then
text = (matches["text"] + "<!-- WARNING: argument omitted, expansion size too large -->")
end
return text
end
def incrementIncludeSize(type, size)
if ((@mIncludeSizes[type] + size) > @mOptions.getMaxIncludeSize) then
return false
else
@mIncludeSizes[type] = (@mIncludeSizes[type] + size)
return true
end
end
def stripNoGallery(text)
mw = MagicWord.get("nogallery")
@mOutput.mNoGallery=(mw.matchAndRemove(text))
end
def stripToc(text)
mw = MagicWord.get("notoc")
@mShowToc = false if mw.matchAndRemove(text)
mw = MagicWord.get("toc")
if mw.match(text) then
@mShowToc = true
@mForceTocPosition = true
text = mw.replace("<!--MWTOC-->", text, 1)
text = mw.replace("", text)
end
return text
end
def formatHeadings(text, isMain = true)
(php_global(:wgMaxTocLevel)
php_global(:wgContLang))
doNumberHeadings = @mOptions.getNumberHeadings
if (not @mTitle.quickUserCan("edit")) then
showEditLink = 0
else
showEditLink = @mOptions.getEditSection
end
esw = MagicWord.get("noeditsection")
showEditLink = 0 if esw.matchAndRemove(text)
matches = []
numMatches = preg_match_all("/<H(?P<level>[1-6])(?P<attrib>.*?>)(?P<header>.*?)<\\/H[1-6] *>/i", text, matches)
enoughToc = (@mShowToc and ((numMatches >= 4) or @mForceTocPosition))
mw = MagicWord.get("newsectionlink")
@mOutput.setNewSection(true) if mw.matchAndRemove(text)
mw = MagicWord.get("forcetoc")
if mw.matchAndRemove(text) then
@mShowToc = true
enoughToc = true
end
enoughToc = false if (numMatches < 1)
sk = @mOptions.getSkin
headlineCount = 0
sectionCount = 0
toc = ""
full = ""
head = []
sublevelCount = []
levelCount = []
toclevel = 0
level = 0
prevlevel = 0
toclevel = 0
prevtoclevel = 0
matches[3].each do |headline|
istemplate = 0
templatetitle = ""
templatesection = 0
numbering = ""
mat = []
if preg_match("/<!--MWTEMPLATESECTION=([^&]+)&([^_]+)-->/", headline, mat) then
istemplate = 1
templatetitle = base64_decode(mat[1])
templatesection = (1 + base64_decode(mat[2]).to_i)
headline = preg_replace("/<!--MWTEMPLATESECTION=([^&]+)&([^_]+)-->/", "", headline)
end
if toclevel then
prevlevel = level
prevtoclevel = toclevel
end
level = matches[1][headlineCount]
if (doNumberHeadings or enoughToc) then
if (level > prevlevel) then
toclevel = (toclevel + 1)
sublevelCount[toclevel] = 0
toc = (toc + sk.tocIndent) if (toclevel < wgMaxTocLevel)
else
if ((level < prevlevel) and (toclevel > 1)) then
if ((toclevel == 2) and (level <= levelCount[1])) then
toclevel = 1
else
i = toclevel
while (i > 0) do
if (levelCount[i] == level) then
toclevel = i
break
else
if (levelCount[i] < level) then
toclevel = (i + 1)
break
end
end
i = (i - 1)
end
end
if (toclevel < wgMaxTocLevel) then
toc = (toc + sk.tocUnindent((prevtoclevel - toclevel)))
end
else
toc = (toc + sk.tocLineEnd) if (toclevel < wgMaxTocLevel)
end
end
levelCount[toclevel] = level
begin
sublevelCount[toclevel] += 1
rescue Exception
# do nothing
end
dot = 0
(i = 1
while (i <= toclevel) do
if (not empty(sublevelCount[i])) then
numbering = (numbering + ".") if dot
numbering = (numbering + wgContLang.formatNum(sublevelCount[i]))
dot = 1
end
i = (i + 1)
end)
end
canonized_headline = @mStripState.unstripBoth(headline)
canonized_headline = preg_replace("/<!--LINK ([0-9]*)-->/e", "$this->mLinkHolders['texts'][$1]", canonized_headline)
canonized_headline = preg_replace("/<!--IWLINK ([0-9]*)-->/e", "$this->mInterwikiLinkHolders['texts'][$1]", canonized_headline)
canonized_headline = preg_replace("/<.*?>/", "", canonized_headline)
tocline = trim(canonized_headline)
headline_hint = trim(canonized_headline)
canonized_headline = Sanitizer.escapeId(tocline)
refers[headlineCount] = canonized_headline
if defined?(refers[canonized_headline]) then
refers[canonized_headline] += 1
else
refers[canonized_headline] = 1
end
refcount[headlineCount] = refers[canonized_headline]
if (doNumberHeadings and (count(matches[3]) > 1)) then
headline = (numbering + (" " + headline))
end
anchor = canonized_headline
if (refcount[headlineCount] > 1) then
anchor = (anchor + ("_" + refcount[headlineCount]))
end
if (enoughToc and ((not defined?(wgMaxTocLevel)) or (toclevel < wgMaxTocLevel))) then
toc = (toc + sk.tocLine(anchor, tocline, numbering, toclevel))
end
if (showEditLink and ((not istemplate) or (not (templatetitle == "")))) then
if istemplate then
editlink = sk.editSectionLinkForOther(templatetitle, templatesection)
else
editlink = sk.editSectionLink(@mTitle, (sectionCount + 1), headline_hint)
end
else
editlink = ""
end
head[headlineCount] = sk.makeHeadline(level, matches["attrib"][headlineCount], anchor, headline, editlink)
headlineCount = (headlineCount + 1)
sectionCount = (sectionCount + 1) if (not istemplate)
end
if enoughToc then
toc = (toc + sk.tocUnindent((toclevel - 1))) if (toclevel < wgMaxTocLevel)
toc = sk.tocList(toc)
end
blocks = preg_split("/<H[1-6].*?>.*?<\\/H[1-6]>/i", text)
i = 0
blocks.each do |block|
unless (((showEditLink and (headlineCount > 0)) and (i == 0)) and (not (block == "\n"))) then
end
full = (full + block)
if (((enoughToc and (not i)) and isMain) and (not @mForceTocPosition)) then
full = (full + toc)
end
full = (full + head[i]) if (not empty(head[i]))
i = (i + 1)
end
if @mForceTocPosition then
return str_replace("<!--MWTOC-->", toc, full)
else
return full
end
end
def preSaveTransform(text, title, user, options, clearState = true)
@mOptions = options
@mTitle = title
self.setOutputType(OT_WIKI)
self.clearState if clearState
stripState = StripState.new
pairs = { "\r\n" => "\n" }
text = str_replace(array_keys(pairs), array_values(pairs), text)
text = self.strip(text, stripState, true, ["gallery"])
text = self.pstPass2(text, stripState, user)
text = stripState.unstripBoth(text)
return text
end
def pstPass2(text, stripState, user)
(php_global(:wgContLang)
php_global(:wgLocaltimezone))
if defined?(wgLocaltimezone) then
oldtz = getenv("TZ")
putenv(("TZ=" + wgLocaltimezone))
end
d = (wgContLang.timeanddate(date("YmdHis"), false, false) + (" (" + (date("T") + ")")))
putenv(("TZ=" + oldtz)) if defined?(wgLocaltimezone)
text = self.replaceVariables(text)
text = self.strip(text, stripState, false, ["gallery"])
sigText = self.getUserSig(user)
text = strtr(text, "~~~~~" => (d), "~~~~" => (("" + (sigText + (" " + d)))), "~~~" => (sigText))
php_global(:wgLegalTitleChars)
tc = ("[" + (wgLegalTitleChars + "]"))
nc = "[ _0-9A-Za-z\\x80-\\xff]"
p1 = ("/\\[\\[(:?" + (nc + ("+:|:|)(" + (tc + ("+?)( \\(" + (tc + "+\\))\\|]]/"))))))
p3 = ("/\\[\\[(:?" + (nc + ("+:|:|)(" + (tc + ("+?)( \\(" + (tc + ("+\\)|)(, " + (tc + "+|)\\|]]/"))))))))
p2 = ("/\\[\\[\\|(" + (tc + "+)]]/"))
text = preg_replace(p1, "[[\\1\\2\\3|\\2]]", text)
text = preg_replace(p3, "[[\\1\\2\\3\\4|\\2]]", text)
t = @mTitle.getText
m = []
if preg_match(("/^(" + (nc + ("+:|)" + (tc + ("+?( \\(" + (tc + "+\\))$/")))))), t, m) then
text = preg_replace(p2, ("[[" + (m[1] + ("\\1" + (m[2] + "|\\1]]")))), text)
else
if (preg_match(("/^(" + (nc + ("+:|)" + (tc + ("+?(, " + (tc + "+|)$/")))))), t, m) and (not ("" == ("" + (m[1] + m[2]))))) then
text = preg_replace(p2, ("[[" + (m[1] + ("\\1" + (m[2] + "|\\1]]")))), text)
else
text = preg_replace(p2, "[[\\1]]", text)
end
end
text = rtrim(text)
return text
end
def getUserSig(user)
username = user.getName
nickname = user.getOption("nickname")
nickname = (nickname == "") ? (username) : (nickname)
if (not (user.getBoolOption("fancysig") == false)) then
if (not (self.validateSig(nickname) == false)) then
return self.cleanSig(nickname, true)
else
nickname = username
wfDebug(("Parser::getUserSig: " + (username + " has bad XML tags in signature.\n")))
end
end
nickname = self.cleanSigInSig(nickname)
userpage = user.getUserPage
return ("[[" + (userpage.getPrefixedText + ("|" + (wfEscapeWikiText(nickname) + "]]"))))
end
def validateSig(text)
return wfIsWellFormedXmlFragment(text) ? (text) : (false)
end
def cleanSig(text, parsing = false)
php_global(:wgTitle)
self.startExternalParse(wgTitle, ParserOptions.new, parsing ? (OT_WIKI) : (OT_MSG))
substWord = MagicWord.get("subst")
substRegex = ("/\\{\\{(?!(?:" + (substWord.getBaseRegex + ("))/x" + substWord.getRegexCase)))
substText = ("{{" + substWord.getSynonym(0))
text = preg_replace(substRegex, substText, text)
text = self.cleanSigInSig(text)
text = self.replaceVariables(text)
self.clearState
return text
end
def cleanSigInSig(text)
text = preg_replace("/~{3,5}/", "", text)
return text
end
def startExternalParse(title, options, outputType, clearState = true)
@mTitle = title
@mOptions = options
self.setOutputType(outputType)
self.clearState if clearState
end
def transformMsg(text, options)
php_global(:wgTitle)
php_static_var(:static => (true))
fname = "Parser::transformMsg"
return text if executing
executing = true
wfProfileIn(fname)
if (wgTitle and (not wgTitle.is_a?(FakeTitle))) then
@mTitle = wgTitle
else
@mTitle = Title.newFromText("msg")
end
@mOptions = options
self.setOutputType(OT_MSG)
self.clearState
text = self.replaceVariables(text)
executing = false
wfProfileOut(fname)
return text
end
def setHook(tag, callback)
tag = strtolower(tag)
oldVal = defined?(@mTagHooks[tag]) ? (@mTagHooks[tag]) : (nil)
@mTagHooks[tag] = callback
return oldVal
end
def setFunctionHook(id, callback, flags = 0)
oldVal = defined?(@mFunctionHooks[id]) ? (@mFunctionHooks[id]) : (nil)
@mFunctionHooks[id] = callback
mw = MagicWord.get(id)
if (not mw) then
raise(MWException.new("Parser::setFunctionHook() expecting a magic word identifier."))
end
synonyms = mw.getSynonyms
sensitive = intval(mw.isCaseSensitive)
synonyms.each do |syn|
syn = strtolower(syn) if (not sensitive)
syn = ("#" + syn) if (not flags.&(SFH_NO_HASH))
syn = substr(syn, 0, -1) if (substr(syn, -1, 1) == ":")
@mFunctionSynonyms[sensitive][syn] = id
end
return oldVal
end
def getFunctionHooks
return array_keys(@mFunctionHooks)
end
def replaceLinkHolders(text, options = 0)
php_global(:wgUser)
php_global(:wgContLang)
fname = "Parser::replaceLinkHolders"
wfProfileIn(fname)
pdbks = []
colours = []
sk = @mOptions.getSkin
linkCache = LinkCache.singleton
if (not empty(@mLinkHolders["namespaces"])) then
wfProfileIn((fname + "-check"))
dbr = wfGetDB(DB_SLAVE)
page = dbr.tableName("page")
threshold = wgUser.getOption("stubthreshold")
asort(@mLinkHolders["namespaces"])
query = false
current = nil
@mLinkHolders["namespaces"].each do |ns|
title = @mLinkHolders["titles"][key]
next if is_null(title)
pdbk = pdbks[key] = title.getPrefixedDBkey
if title.isAlwaysKnown then
colours[pdbk] = 1
else
if (not ((id = linkCache.getGoodLinkID(pdbk)) == 0)) then
colours[pdbk] = 1
@mOutput.addLink(title, id)
else
if linkCache.isBadLink(pdbk) then
colours[pdbk] = 0
else
if (not defined?(current)) then
current = ns
query = "SELECT page_id, page_namespace, page_title"
query = (query + ", page_len, page_is_redirect") if (threshold > 0)
query = (query + (" FROM " + (page + (" WHERE (page_namespace=" + (ns + " AND page_title IN(")))))
else
if (not (current == ns)) then
current = ns
query = (query + (")) OR (page_namespace=" + (ns + " AND page_title IN(")))
else
query = (query + ", ")
end
end
query = (query + dbr.addQuotes(@mLinkHolders["dbkeys"][key]))
end
end
end
end
if query then
query = (query + "))")
query = (query + " FOR UPDATE") if options.&(RLH_FOR_UPDATE)
res = dbr.query(query, fname)
while s = dbr.fetchObject(res) do
title = Title.makeTitle(s.page_namespace, s.page_title)
pdbk = title.getPrefixedDBkey
linkCache.addGoodLinkObj(s.page_id, title)
@mOutput.addLink(title, s.page_id)
if (threshold > 0) then
size = s.page_len
if ((s.page_is_redirect or (not (s.page_namespace == 0))) or (size >= threshold)) then
colours[pdbk] = 1
else
colours[pdbk] = 2
end
else
colours[pdbk] = 1
end
end
end
wfProfileOut((fname + "-check"))
if wgContLang.hasVariants then
linkBatch = LinkBatch.new
variantMap = []
categoryMap = []
varCategories = []
categories = @mOutput.getCategoryLinks
@mLinkHolders["namespaces"].each do |ns|
title = @mLinkHolders["titles"][key]
next if is_null(title)
pdbk = title.getPrefixedDBkey
titleText = title.getText
allTextVariants = wgContLang.convertLinkToAllVariants(titleText)
if (not defined?(colours[pdbk])) then
allTextVariants.each do |textVariant|
if (not (textVariant == titleText)) then
variantTitle = Title.makeTitle(ns, textVariant)
next if is_null(variantTitle)
linkBatch.addObj(variantTitle)
(variantMap[variantTitle.getPrefixedDBkey] << key)
end
end
end
end
categories.each do |category|
variants = wgContLang.convertLinkToAllVariants(category)
variants.each do |variant|
if (not (variant == category)) then
variantTitle = Title.newFromDBkey(Title.makeName(NS_CATEGORY, variant))
next if is_null(variantTitle)
linkBatch.addObj(variantTitle)
categoryMap[variant] = category
end
end
end
if (not linkBatch.isEmpty) then
titleClause = linkBatch.constructSet("page", dbr)
variantQuery = "SELECT page_id, page_namespace, page_title"
if (threshold > 0) then
variantQuery = (variantQuery + ", page_len, page_is_redirect")
end
variantQuery = (variantQuery + (" FROM " + (page + (" WHERE " + titleClause))))
variantQuery = (variantQuery + " FOR UPDATE") if options.&(RLH_FOR_UPDATE)
varRes = dbr.query(variantQuery, fname)
while s = dbr.fetchObject(varRes) do
variantTitle = Title.makeTitle(s.page_namespace, s.page_title)
varPdbk = variantTitle.getPrefixedDBkey
vardbk = variantTitle.getDBkey
holderKeys = []
if defined?(variantMap[varPdbk]) then
holderKeys = variantMap[varPdbk]
linkCache.addGoodLinkObj(s.page_id, variantTitle)
@mOutput.addLink(variantTitle, s.page_id)
end
holderKeys.each do |key|
title = @mLinkHolders["titles"][key]
next if is_null(title)
pdbk = title.getPrefixedDBkey
if (not defined?(colours[pdbk])) then
@mLinkHolders["titles"][key] = variantTitle
@mLinkHolders["dbkeys"][key] = variantTitle.getDBkey
pdbks[key] = varPdbk
if (threshold > 0) then
size = s.page_len
if ((s.page_is_redirect or (not (s.page_namespace == 0))) or (size >= threshold)) then
colours[varPdbk] = 1
else
colours[varPdbk] = 2
end
else
colours[varPdbk] = 1
end
end
end
if defined?(categoryMap[vardbk]) then
oldkey = categoryMap[vardbk]
varCategories[oldkey] = vardbk if (not (oldkey == vardbk))
end
end
if (count(varCategories) > 0) then
newCats = []
originalCats = @mOutput.getCategories
originalCats.each do |sortkey|
if array_key_exists(cat, varCategories) then
newCats[varCategories[cat]] = sortkey
else
newCats[cat] = sortkey
end
end
@mOutput.setCategoryLinks(newCats)
end
end
end
wfProfileIn((fname + "-construct"))
replacePairs = []
@mLinkHolders["namespaces"].each do |ns|
pdbk = pdbks[key]
searchkey = ("<!--LINK " + (key + "-->"))
title = @mLinkHolders["titles"][key]
if empty(colours[pdbk]) then
linkCache.addBadLinkObj(title)
colours[pdbk] = 0
@mOutput.addLink(title, 0)
replacePairs[searchkey] = sk.makeBrokenLinkObj(title, @mLinkHolders["texts"][key], @mLinkHolders["queries"][key])
else
if (colours[pdbk] == 1) then
replacePairs[searchkey] = sk.makeKnownLinkObj(title, @mLinkHolders["texts"][key], @mLinkHolders["queries"][key])
else
if (colours[pdbk] == 2) then
replacePairs[searchkey] = sk.makeStubLinkObj(title, @mLinkHolders["texts"][key], @mLinkHolders["queries"][key])
end
end
end
end
replacer = HashtableReplacer.new(replacePairs, 1)
wfProfileOut((fname + "-construct"))
wfProfileIn((fname + "-replace"))
text = preg_replace_callback("/(<!--LINK .*?-->)/", replacer.cb, text)
wfProfileOut((fname + "-replace"))
end
if (not empty(@mInterwikiLinkHolders["texts"])) then
wfProfileIn((fname + "-interwiki"))
replacePairs = []
@mInterwikiLinkHolders["texts"].each do |link|
title = @mInterwikiLinkHolders["titles"][key]
replacePairs[key] = sk.makeLinkObj(title, link)
end
replacer = HashtableReplacer.new(replacePairs, 1)
text = preg_replace_callback("/<!--IWLINK (.*?)-->/", replacer.cb, text)
wfProfileOut((fname + "-interwiki"))
end
wfProfileOut(fname)
return colours
end
def replaceLinkHoldersText(text)
fname = "Parser::replaceLinkHoldersText"
wfProfileIn(fname)
text = preg_replace_callback("/<!--(LINK|IWLINK) (.*?)-->/", [self, "replaceLinkHoldersTextCallback"], text)
wfProfileOut(fname)
return text
end
def replaceLinkHoldersTextCallback(matches)
type = matches[1]
key = matches[2]
if (type == "LINK") then
return @mLinkHolders["texts"][key] if defined?(@mLinkHolders["texts"][key])
else
if (type == "IWLINK") then
if defined?(@mInterwikiLinkHolders["texts"][key]) then
return @mInterwikiLinkHolders["texts"][key]
end
end
end
return matches[0]
end
def renderPreTag(text, attribs)
content = StringUtils.delimiterReplace("<nowiki>", "</nowiki>", "$1", text, "i")
attribs = Sanitizer.validateTagAttributes(attribs, "pre")
return (wfOpenElement("pre", attribs) + (Xml.escapeTagsOnly(content) + "</pre>"))
end
def renderImageGallery(text, params)
ig = ImageGallery.new
ig.setContextTitle(@mTitle)
ig.setShowBytes(false)
ig.setShowFilename(false)
ig.setParsing
ig.useSkin(@mOptions.getSkin)
if defined?(params["caption"]) then
caption = params["caption"]
caption = htmlspecialchars(caption)
caption = self.replaceInternalLinks(caption)
ig.setCaptionHtml(caption)
end
ig.setPerRow(params["perrow"]) if defined?(params["perrow"])
ig.setWidths(params["widths"]) if defined?(params["widths"])
ig.setHeights(params["heights"]) if defined?(params["heights"])
lines = explode("\n", text)
lines.each do |line|
matches = []
preg_match("/^([^|]+)(\\|(.*))?$/", line, matches)
next if (count(matches) == 0)
tp = Title.newFromText(matches[1])
nt = tp
next if is_null(nt)
defined?(matches[3]) ? (label = matches[3]) : (label = "")
pout = self.parse(label, @mTitle, @mOptions, false, false)
html = pout.getText
ig.add(Image.new(nt), html)
@mOutput.addImage(nt.getDBkey) if (nt.getNamespace == NS_IMAGE)
end
return ig.toHTML
end
def makeImage(nt, options)
part = array_map("trim", explode("|", options))
mwAlign = []
alignments = ["left", "right", "center", "none", "baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom"]
alignments.each do |alignment|
mwAlign[alignment] = MagicWord.get(("img_" + alignment))
end
mwThumb = MagicWord.get("img_thumbnail")
mwManualThumb = MagicWord.get("img_manualthumb")
mwWidth = MagicWord.get("img_width")
mwFramed = MagicWord.get("img_framed")
mwPage = MagicWord.get("img_page")
caption = ""
params = []
framed = thumb = false
manual_thumb = ""
align = valign = ""
sk = @mOptions.getSkin
Php2Rb.foreach(part) do |val|
if (not is_null(mwThumb.matchVariableStartToEnd(val))) then
thumb = true
else
if (not is_null(match = mwManualThumb.matchVariableStartToEnd(val))) then
thumb = true
manual_thumb = match
else
Php2Rb.foreach(alignments) do |alignment|
if (not is_null(mwAlign[alignment].matchVariableStartToEnd(val))) then
case alignment
when "left", "right", "center", "none" then
align = alignment
else
(valign = alignment)
end
Php2Rb.continue(2)
end
end
if (not is_null(match = mwPage.matchVariableStartToEnd(val))) then
params["page"] = match
else
if ((not defined?(params["width"])) and (not is_null(match = mwWidth.matchVariableStartToEnd(val)))) then
wfDebug(("img_width match: " + (match + "\n")))
m = []
if preg_match("/^([0-9]*)x([0-9]*)$/", match, m) then
params["width"] = intval(m[1])
params["height"] = intval(m[2])
else
params["width"] = intval(match)
end
else
if (not is_null(mwFramed.matchVariableStartToEnd(val))) then
framed = true
else
caption = val
end
end
end
end
end
end
alt = self.replaceLinkHoldersText(caption)
alt = @mStripState.unstripBoth(alt)
alt = Sanitizer.stripAllTags(alt)
return sk.makeImageLinkObj(nt, caption, alt, align, params, framed, thumb, manual_thumb, valign)
end
def disableCache
wfDebug("Parser output marked as uncacheable.\n")
@mOutput.mCacheTime=(-1)
end
def attributeStripCallback(text, args)
text = self.replaceVariables(text, args)
text = @mStripState.unstripBoth(text)
return text
end
def Title(x = nil)
return wfSetVar(@mTitle, x)
end
def Options(x = nil)
return wfSetVar(@mOptions, x)
end
def OutputType(x = nil)
return wfSetVar(@mOutputType, x)
end
def getTags
return array_keys(@mTagHooks)
end
def extractSections(text, section, mode, newtext = "")
stripState = StripState.new
oldOutputType = @mOutputType
oldOptions = @mOptions
@mOptions = ParserOptions.new
self.setOutputType(OT_WIKI)
striptext = self.strip(text, stripState, true)
self.setOutputType(oldOutputType)
@mOptions = oldOptions
uniq = preg_quote(self.uniqPrefix, "/")
comment = ("(?:" + (uniq + "-!--.*?QINU)"))
secs = preg_split(("/\n\t\t\t(\n\t\t\t\t^\n\t\t\t\t(?:" + (comment + ("|<\\/?noinclude>)* # Initial comments will be stripped\n\t\t\t\t(=+) # Should this be limited to 6?\n\t\t\t\t.+? # Section title...\n\t\t\t\t\\2 # Ending = count must match start\n\t\t\t\t(?:" + (comment + "|<\\/?noinclude>|[ \\t]+)* # Trailing whitespace ok\n\t\t\t\t$\n\t\t\t|\n\t\t\t\t<h([1-6])\\b.*?>\n\t\t\t\t.*?\n\t\t\t\t<\\/h\\3\\s*>\n\t\t\t)\n\t\t\t/mix")))), striptext, -1, PREG_SPLIT_DELIM_CAPTURE)
if (mode == "get") then
(section == 0) ? (rv = secs[0]) : (rv = newtext)
else
if (mode == "replace") then
if (section == 0) then
rv = (newtext + "\n\n")
remainder = true
else
rv = secs[0]
remainder = false
end
end
end
count = 0
sectionLevel = 0
(index = 1
while (index < count(secs)) do
(headerLine = secs[index = (index + 1)]
if secs[index] then
headerLevel = strlen(secs[index = (index + 1)])
else
index = (index + 1)
headerLevel = intval(secs[index = (index + 1)])
end
content = secs[index = (index + 1)]
count = (count + 1)
if (mode == "get") then
if (count == section) then
rv = (headerLine + content)
sectionLevel = headerLevel
else
if (count > section) then
if (sectionLevel and (headerLevel > sectionLevel)) then
rv = (rv + (headerLine + content))
else
break
end
end
end
else
if (mode == "replace") then
if (count < section) then
rv = (rv + (headerLine + content))
else
if (count == section) then
rv = (rv + (newtext + "\n\n"))
sectionLevel = headerLevel
else
if (count > section) then
remainder = true if (headerLevel <= sectionLevel)
rv = (rv + (headerLine + content)) if remainder
end
end
end
end
end)
# do nothing
end)
rv = trim(stripState.unstripBoth(rv)) if is_string(rv)
return rv
end
def getSection(text, section, deftext = "")
return self.extractSections(text, section, "get", deftext)
end
def replaceSection(oldtext, section, text)
return self.extractSections(oldtext, section, "replace", text)
end
def getRevisionTimestamp
if is_null(@mRevisionTimestamp) then
wfProfileIn("Parser::getRevisionTimestamp")
php_global(:wgContLang)
dbr = wfGetDB(DB_SLAVE)
timestamp = dbr.selectField("revision", "rev_timestamp", "rev_id" => (@mRevisionId), "Parser::getRevisionTimestamp")
timestamp = wfTimestamp(TS_MW, timestamp)
@mRevisionTimestamp = wgContLang.userAdjust(timestamp, "")
wfProfileOut("Parser::getRevisionTimestamp")
end
return @mRevisionTimestamp
end
def setDefaultSort(sort)
@mDefaultSort = sort
end
def getDefaultSort
if (not (@mDefaultSort == false)) then
return @mDefaultSort
else
return if (@mTitle.getNamespace == NS_CATEGORY) then
@mTitle.getText
else
@mTitle.getPrefixedText
end
end
end
end
class OnlyIncludeReplacer
attr_accessor(:output)
def replace(matches)
if (substr(matches[1], -1) == "\n") then
@output = (@output + substr(matches[1], 0, -1))
else
@output = (@output + matches[1])
end
end
end
class StripState
attr_accessor(:general)
attr_accessor(:nowiki)
def __construct
@general = ReplacementArray.new
@nowiki = ReplacementArray.new
end
def unstripGeneral(text)
wfProfileIn("StripState::unstripGeneral")
text = @general.replace(text)
wfProfileOut("StripState::unstripGeneral")
return text
end
def unstripNoWiki(text)
wfProfileIn("StripState::unstripNoWiki")
text = @nowiki.replace(text)
wfProfileOut("StripState::unstripNoWiki")
return text
end
def unstripBoth(text)
wfProfileIn("StripState::unstripBoth")
text = @general.replace(text)
text = @nowiki.replace(text)
wfProfileOut("StripState::unstripBoth")
return text
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment