var $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
var $mInterwikiLinkHolders, $mLinkHolders;
var $mIncludeSizes, $mPPNodeCount, $mDefaultSort;
- var $mTplExpandCache,// empty-frame expansion cache
- $mTemplatePath; // stores an unsorted hash of all the templates already loaded
- // in this path. Used for loop detection.
+ var $mTplExpandCache; // empty-frame expansion cache
var $mTplRedirCache, $mTplDomCache, $mHeadings;
# Temporary
$this->setFunctionHook( 'special', array( 'CoreParserFunctions', 'special' ) );
$this->setFunctionHook( 'defaultsort', array( 'CoreParserFunctions', 'defaultsort' ), SFH_NO_HASH );
$this->setFunctionHook( 'filepath', array( 'CoreParserFunctions', 'filepath' ), SFH_NO_HASH );
+ $this->setFunctionHook( 'tag', array( 'CoreParserFunctions', 'tagObj' ), SFH_OBJECT_ARGS );
if ( $wgAllowDisplayTitle ) {
$this->setFunctionHook( 'displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH );
$this->mUniqPrefix = "\x7fUNIQ" . Parser::getRandomString();
# Clear these on every parse, bug 4549
- $this->mTemplatePath = array();
$this->mTplExpandCache = $this->mTplRedirCache = $this->mTplDomCache = array();
$this->mShowToc = true;
foreach ( $parts as $partIndex => $part ) {
if ( isset( $piece['eqpos'][$partIndex] ) ) {
$eqpos = $piece['eqpos'][$partIndex];
- list( $ws1, $argName, $ws2 ) = self::splitWhitespace( substr( $part, 0, $eqpos ) );
- list( $ws3, $argValue, $ws4 ) = self::splitWhitespace( substr( $part, $eqpos + 1 ) );
- $element .= "<part>$ws1<name>$argName</name>$ws2=$ws3<value>$argValue</value>$ws4</part>";
+ $argName = substr( $part, 0, $eqpos );
+ $argValue = substr( $part, $eqpos + 1 );
+ $element .= "<part><name>$argName</name>=<value>$argValue</value></part>";
} else {
- list( $ws1, $value, $ws2 ) = self::splitWhitespace( $part );
- $element .= "<part>$ws1<name index=\"$argIndex\" /><value>$value</value>$ws2</part>";
+ $element .= "<part><name index=\"$argIndex\" /><value>$part</value></part>";
$argIndex++;
}
}
$id = $this->mVariables->matchStartToEnd( $part1 );
if ( $id !== false ) {
$text = $this->getVariableValue( $id );
- $this->mOutput->mContainsOldMagic = true;
+ if (MagicWord::getCacheTTL($id)>-1)
+ $this->mOutput->mContainsOldMagic = true;
$found = true;
}
}
}
wfProfileOut( __METHOD__.'-modifiers' );
- # Save path level before recursing into functions & templates.
- $lastPathLevel = $this->mTemplatePath;
-
# Parser functions
if ( !$found ) {
wfProfileIn( __METHOD__ . '-pfunc' );
$wgContLang->findVariantLink($part1, $title);
}
# Do infinite loop check
- if ( isset( $this->mTemplatePath[$titleText] ) ) {
+ if ( isset( $frame->loopCheckHash[$titleText] ) ) {
$found = true;
- $text = "[[$part1]]" . $this->insertStripItem( '<!-- WARNING: template loop detected -->' );
+ $text = "<span class=\"error\">Template loop detected: [[$titleText]]</span>";
wfDebug( __METHOD__.": template loop broken at '$titleText'\n" );
}
+ # Do recursion depth check
+ $limit = $this->mOptions->getMaxTemplateDepth();
+ if ( $frame->depth >= $limit ) {
+ $found = true;
+ $text = "<span class=\"error\">Template recursion depth limit exceeded ($limit)</span>";
+ }
}
}
# Recover the source wikitext and return it
if ( !$found ) {
$text = '{{' . $frame->implode( '|', $titleWithSpaces, $args ) . '}}';
- # Prune lower levels off the recursion check path
- $this->mTemplatePath = $lastPathLevel;
wfProfileOut( $fname );
return $text;
}
if ( $isDOM ) {
# Clean up argument array
$newFrame = $frame->newChild( $args, $title );
- # Add a new element to the templace recursion path
- $this->mTemplatePath[$titleText] = 1;
+ # Add a new element to the templace loop detection hashtable
+ $newFrame->loopCheckHash[$titleText] = true;
if ( $titleText !== false && count( $newFrame->args ) == 0 ) {
# Expansion is eligible for the empty-frame cache
$this->mTplExpandCache[$titleText] = $text;
}
} else {
+ # Uncached expansion
$text = $newFrame->expand( $text );
}
}
$text = "\n" . $text;
}
- # Prune lower levels off the recursion check path
- $this->mTemplatePath = $lastPathLevel;
-
if ( !$this->incrementIncludeSize( 'post-expand', strlen( $text ) ) ) {
# Error, oversize inclusion
$text = "[[$originalTitle]]" .
$arg = trim( $argWithSpaces );
if ( isset( $frame->args[$arg] ) ) {
+ # Found template argument
$text = $frame->parent->expand( $frame->args[$arg] );
} else if ( ( $this->ot['html'] || $this->ot['pre'] ) && $parts->length > 0 ) {
+ # No match in frame, use the supplied default
$text = $frame->expand( $parts->item( 0 ) );
}
if ( !$this->incrementIncludeSize( 'arg', strlen( $text ) ) ) {
}
if ( $text === false ) {
+ # No match anywhere
$text = '{{{' . $frame->implode( '|', $argWithSpaces, $parts ) . '}}}';
}
if ( $error !== false ) {
*
* @param array $params Associative array of parameters:
* name DOMNode for the tag name
- * attrText DOMNode for unparsed text where tag attributes are thought to be
+ * attr DOMNode for unparsed text where tag attributes are thought to be
+ * attributes Optional associative array of parsed attributes
* inner Contents of extension element
* noClose Original text did not have a close tag
* @param PPFrame $frame
static $n = 1;
$name = $frame->expand( $params['name'] );
- $attrText = is_null( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
- $content = is_null( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
+ $attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
+ $content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
$marker = "{$this->mUniqPrefix}-$name-" . sprintf('%08X', $n++) . $this->mMarkerSuffix;
if ( $this->ot['html'] ) {
$name = strtolower( $name );
- $params = Sanitizer::decodeTagAttributes( $attrText );
+ $attributes = Sanitizer::decodeTagAttributes( $attrText );
+ if ( isset( $params['attributes'] ) ) {
+ $attributes = $attributes + $params['attributes'];
+ }
switch ( $name ) {
case 'html':
if( $wgRawHtml ) {
break;
case 'math':
$output = $wgContLang->armourMath(
- MathRenderer::renderMath( $content, $params ) );
+ MathRenderer::renderMath( $content, $attributes ) );
break;
case 'gallery':
- $output = $this->renderImageGallery( $content, $params );
+ $output = $this->renderImageGallery( $content, $attributes );
break;
default:
if( isset( $this->mTagHooks[$name] ) ) {
$output = call_user_func_array( $this->mTagHooks[$name],
- array( $content, $params, $this ) );
+ array( $content, $attributes, $this ) );
} else {
throw new MWException( "Invalid call hook $name" );
}
* found The text returned is valid, stop processing the template. This
* is on by default.
* nowiki Wiki markup in the return value should be escaped
- * noparse Unsafe HTML tags should not be stripped, etc.
- * noargs Don't replace triple-brace arguments in the return value
* isHTML The returned text is HTML, armour it against wikitext transformation
*
* @public
var $parser, $title;
var $titleCache;
+ /**
+ * Hashtable listing templates which are disallowed for expansion in this frame,
+ * having been encountered previously in parent frames.
+ */
+ var $loopCheckHash;
+
+ /**
+ * Recursion depth of this frame, top = 0
+ */
+ var $depth;
+
const NO_ARGS = 1;
const NO_TEMPLATES = 2;
const STRIP_COMMENTS = 4;
$this->parser = $parser;
$this->title = $parser->mTitle;
$this->titleCache = array( $this->title ? $this->title->getPrefixedDBkey() : false );
+ $this->loopCheckHash = array();
+ $this->depth = 0;
}
/**
* Expansion frame with template arguments
*/
class PPTemplateFrame extends PPFrame {
- var $parser, $args, $parent;
- var $titleCache;
+ var $args, $parent;
function __construct( $parser, $parent = false, $args = array(), $title = false ) {
$this->parser = $parser;
$this->title = $title;
$this->titleCache = $parent->titleCache;
$this->titleCache[] = $title ? $title->getPrefixedDBkey() : false;
+ $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
+ $this->depth = $parent->depth + 1;
}
function __toString() {