* (bug 6701) Kazakh language variants in MessagesEn.php
[lhc/web/wiklou.git] / includes / Parser.php
index 604cb44..6bcfcff 100644 (file)
@@ -19,6 +19,7 @@ define( 'RLH_FOR_UPDATE', 1 );
 define( 'OT_HTML', 1 );
 define( 'OT_WIKI', 2 );
 define( 'OT_MSG' , 3 );
+define( 'OT_PREPROCESS', 4 );
 
 # Flags for setFunctionHook
 define( 'SFH_NO_HASH', 1 );
@@ -108,6 +109,7 @@ class Parser
        var $mOptions,      // ParserOptions object
                $mTitle,        // Title context, used for self-link rendering and similar things
                $mOutputType,   // Output type, one of the OT_xxx constants
+               $ot,            // Shortcut alias, see setOutputType()
                $mRevisionId;   // ID to display in {{REVISIONID}} tags
 
        /**#@-*/
@@ -156,6 +158,9 @@ class Parser
                $this->setFunctionHook( 'numberoffiles', array( 'CoreParserFunctions', 'numberoffiles' ), SFH_NO_HASH );
                $this->setFunctionHook( 'numberofadmins', array( 'CoreParserFunctions', 'numberofadmins' ), SFH_NO_HASH );
                $this->setFunctionHook( 'language', array( 'CoreParserFunctions', 'language' ), SFH_NO_HASH );
+               $this->setFunctionHook( 'padleft', array( 'CoreParserFunctions', 'padleft' ), SFH_NO_HASH );
+               $this->setFunctionHook( 'padright', array( 'CoreParserFunctions', 'padright' ), SFH_NO_HASH );
+               $this->setFunctionHook( 'anchorencode', array( 'CoreParserFunctions', 'anchorencode' ), SFH_NO_HASH );
 
                if ( $wgAllowDisplayTitle ) {
                        $this->setFunctionHook( 'displaytitle', array( 'CoreParserFunctions', 'displaytitle' ), SFH_NO_HASH );
@@ -226,6 +231,17 @@ class Parser
                wfProfileOut( __METHOD__ );
        }
 
+       function setOutputType( $ot ) {
+               $this->mOutputType = $ot;
+               // Shortcut alias
+               $this->ot = array(
+                       'html' => $ot == OT_HTML,
+                       'wiki' => $ot == OT_WIKI,
+                       'msg' => $ot == OT_MSG,
+                       'pre' => $ot == OT_PREPROCESS,
+               );
+       }
+
        /**
         * Accessor for mUniqPrefix.
         *
@@ -268,7 +284,7 @@ class Parser
                if( $revid !== null ) {
                        $this->mRevisionId = $revid;
                }
-               $this->mOutputType = OT_HTML;
+               $this->setOutputType( OT_HTML );
 
                //$text = $this->strip( $text, $this->mStripState );
                // VOODOO MAGIC FIX! Sometimes the above segfaults in PHP5.
@@ -373,6 +389,30 @@ class Parser
                return $text;
        }
 
+       /**
+        * Expand templates and variables in the text, producing valid, static wikitext.
+        * Also removes comments.
+        */
+       function preprocess( $text, $title, $options ) {
+               wfProfileIn( __METHOD__ );
+               $this->clearState();
+               $this->setOutputType( OT_PREPROCESS );
+               $this->mOptions = $options;
+               $this->mTitle = $title;
+               $x =& $this->mStripState;
+               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$x ) );
+               $text = $this->strip( $text, $x );
+               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$x ) );
+               if ( $this->mOptions->getRemoveComments() ) {
+                       $text = Sanitizer::removeHTMLcomments( $text );
+               }
+               $text = $this->replaceVariables( $text );
+               $text = $this->unstrip( $text, $x );
+               $text = $this->unstripNowiki( $text, $x );
+               wfProfileOut( __METHOD__ );
+               return $text;
+       }
+
        /**
         * Get a random string
         *
@@ -491,9 +531,7 @@ class Parser
                wfProfileIn( __METHOD__ );
                $render = ($this->mOutputType == OT_HTML);
 
-               # Replace any instances of the placeholders
                $uniq_prefix = $this->mUniqPrefix;
-               #$text = str_replace( $uniq_prefix, wfHtmlEscapeFirst( $uniq_prefix ), $text );
                $commentState = array();
                
                $elements = array_merge(
@@ -1469,7 +1507,6 @@ class Parser
                }
 
                $selflink = $this->mTitle->getPrefixedText();
-               $checkVariantLink = sizeof($wgContLang->getVariants())>1;
                $useSubpages = $this->areSubpagesAllowed();
                wfProfileOut( $fname.'-setup' );
 
@@ -1564,13 +1601,6 @@ class Parser
                                continue;
                        }
 
-                       #check other language variants of the link
-                       #if the article does not exist
-                       if( $checkVariantLink
-                           && $nt->getArticleID() == 0 ) {
-                               $wgContLang->findVariantLink($link, $nt);
-                       }
-
                        $ns = $nt->getNamespace();
                        $iw = $nt->getInterWiki();
                        wfProfileOut( "$fname-title" );
@@ -1710,6 +1740,7 @@ class Parser
                                        // upload on the shared repository, and we want to see its
                                        // auto-generated page.
                                        $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix );
+                                       $this->mOutput->addLink( $nt );
                                        continue;
                                }
                        }
@@ -2298,6 +2329,25 @@ class Parser
                $ts = time();
                wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
 
+               # Use the time zone
+               global $wgLocaltimezone;
+               if ( isset( $wgLocaltimezone ) ) {
+                       $oldtz = getenv( 'TZ' );
+                       putenv( 'TZ='.$wgLocaltimezone );
+               }
+               $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 );
+               if ( isset( $wgLocaltimezone ) ) {
+                       putenv( 'TZ='.$oldtz );
+               }
+
                switch ( $index ) {
                        case 'currentmonth':
                                return $varCache[$index] = $wgContLang->formatNum( date( 'm', $ts ) );
@@ -2311,6 +2361,18 @@ class Parser
                                return $varCache[$index] = $wgContLang->formatNum( date( 'j', $ts ) );
                        case 'currentday2':
                                return $varCache[$index] = $wgContLang->formatNum( date( 'd', $ts ) );
+                       case 'localmonth':
+                               return $varCache[$index] = $wgContLang->formatNum( $localMonth );
+                       case 'localmonthname':
+                               return $varCache[$index] = $wgContLang->getMonthName( $localMonthName );
+                       case 'localmonthnamegen':
+                               return $varCache[$index] = $wgContLang->getMonthNameGen( $localMonthName );
+                       case 'localmonthabbrev':
+                               return $varCache[$index] = $wgContLang->getMonthAbbreviation( $localMonthName );
+                       case 'localday':
+                               return $varCache[$index] = $wgContLang->formatNum( $localDay );
+                       case 'localday2':
+                               return $varCache[$index] = $wgContLang->formatNum( $localDay2 );
                        case 'pagename':
                                return $this->mTitle->getText();
                        case 'pagenamee':
@@ -2367,12 +2429,28 @@ class Parser
                                return $varCache[$index] = $wgContLang->formatNum( date( 'Y', $ts ), true );
                        case 'currenttime':
                                return $varCache[$index] = $wgContLang->time( wfTimestamp( TS_MW, $ts ), false, false );
+                       case 'currenthour':
+                               return $varCache[$index] = $wgContLang->formatNum( date( 'H', $ts ), true );
                        case 'currentweek':
                                // @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
                                // int to remove the padding
                                return $varCache[$index] = $wgContLang->formatNum( (int)date( 'W', $ts ) );
                        case 'currentdow':
                                return $varCache[$index] = $wgContLang->formatNum( date( 'w', $ts ) );
+                       case 'localdayname':
+                               return $varCache[$index] = $wgContLang->getWeekdayName( $localDayOfWeek + 1 );
+                       case 'localyear':
+                               return $varCache[$index] = $wgContLang->formatNum( $localYear, true );
+                       case 'localtime':
+                               return $varCache[$index] = $wgContLang->time( $localTimestamp, false, false );
+                       case 'localhour':
+                               return $varCache[$index] = $wgContLang->formatNum( $localHour, true );
+                       case 'localweek':
+                               // @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to
+                               // int to remove the padding
+                               return $varCache[$index] = $wgContLang->formatNum( (int)$localWeek );
+                       case 'localdow':
+                               return $varCache[$index] = $wgContLang->formatNum( $localDayOfWeek );
                        case 'numberofarticles':
                                return $varCache[$index] = $wgContLang->formatNum( wfNumberOfArticles() );
                        case 'numberoffiles':
@@ -2385,9 +2463,10 @@ class Parser
                                return $varCache[$index]  = $wgContLang->formatNum( wfNumberOfAdmins() );
                        case 'currenttimestamp':
                                return $varCache[$index] = wfTimestampNow();
+                       case 'localtimestamp':
+                               return $varCache[$index] = $localTimestamp;
                        case 'currentversion':
-                               global $wgVersion;
-                               return $wgVersion;
+                               return $varCache[$index] = SpecialVersion::getVersion();
                        case 'sitename':
                                return $wgSitename;
                        case 'server':
@@ -2629,7 +2708,7 @@ class Parser
                if ( !$argsOnly ) {
                        $braceCallbacks[2] = array( &$this, 'braceSubstitution' );
                }
-               if ( $this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI ) {
+               if ( $this->mOutputType != OT_MSG ) {
                        $braceCallbacks[3] = array( &$this, 'argSubstitution' );
                }
                if ( $braceCallbacks ) {
@@ -2740,10 +2819,11 @@ class Parser
 
                $linestart = '';
 
+                       
                # $part1 is the bit before the first |, and must contain only title characters
                # $args is a list of arguments, starting from index 0, not including $part1
 
-               $part1 = $piece['title'];
+               $titleText = $part1 = $piece['title'];
                # If the third subpattern matched anything, it will start with |
 
                if (null == $piece['parts']) {
@@ -2764,7 +2844,7 @@ class Parser
                wfProfileIn( __METHOD__.'-modifiers' );
                if ( !$found ) {
                        $mwSubst =& MagicWord::get( 'subst' );
-                       if ( $mwSubst->matchStartAndRemove( $part1 ) xor ($this->mOutputType == OT_WIKI) ) {
+                       if ( $mwSubst->matchStartAndRemove( $part1 ) xor $this->ot['wiki'] ) {
                                # One of two possibilities is true:
                                # 1) Found SUBST but not in the PST phase
                                # 2) Didn't find SUBST and in the PST phase
@@ -2862,8 +2942,7 @@ class Parser
                                $noargs = true;
                                $found = true;
                                $text = $linestart .
-                                       '{{' . $part1 . '}}' .
-                                       '<!-- WARNING: template loop detected -->';
+                                       "[[$part1]]<!-- WARNING: template loop detected -->";
                                wfDebug( __METHOD__.": template loop broken at '$part1'\n" );
                        } else {
                                # set $text to cached message.
@@ -2888,6 +2967,7 @@ class Parser
 
 
                        if ( !is_null( $title ) ) {
+                               $titleText = $title->getPrefixedText();
                                $checkVariantLink = sizeof($wgContLang->getVariants())>1;
                                # Check for language variants if the template is not found
                                if($checkVariantLink && $title->getArticleID() == 0){
@@ -2895,7 +2975,7 @@ class Parser
                                }
 
                                if ( !$title->isExternal() ) {
-                                       if ( $title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() && $this->mOutputType != OT_WIKI ) {
+                                       if ( $title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() && $this->ot['html'] ) {
                                                $text = SpecialPage::capturePath( $title );
                                                if ( is_string( $text ) ) {
                                                        $found = true;
@@ -2914,13 +2994,13 @@ class Parser
                                        }
 
                                        # If the title is valid but undisplayable, make a link to it
-                                       if ( $this->mOutputType == OT_HTML && !$found ) {
-                                               $text = '[['.$title->getPrefixedText().']]';
+                                       if ( !$found && ( $this->ot['html'] || $this->ot['pre'] ) ) {
+                                               $text = "[[$titleText]]";
                                                $found = true;
                                        }
                                } elseif ( $title->isTrans() ) {
                                        // Interwiki transclusion
-                                       if ( $this->mOutputType == OT_HTML && !$forceRawInterwiki ) {
+                                       if ( $this->ot['html'] && !$forceRawInterwiki ) {
                                                $text = $this->interwikiTransclude( $title, 'render' );
                                                $isHTML = true;
                                                $noparse = true;
@@ -2949,17 +3029,16 @@ class Parser
                if ( $found && !$this->incrementIncludeSize( 'pre-expand', strlen( $text ) ) ) {
                        # Error, oversize inclusion
                        $text = $linestart .
-                               '{{' . $part1 . '}}' .
-                               '<!-- WARNING: template omitted, pre-expand include size too large -->';
+                               "[[$titleText]]<!-- WARNING: template omitted, pre-expand include size too large -->";
                        $noparse = true;
                        $noargs = true;
                }
 
                # Recursive parsing, escaping and link table handling
                # Only for HTML output
-               if ( $nowiki && $found && $this->mOutputType == OT_HTML ) {
+               if ( $nowiki && $found && ( $this->ot['html'] || $this->ot['pre'] ) ) {
                        $text = wfEscapeWikiText( $text );
-               } elseif ( ($this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI) && $found ) {
+               } elseif ( !$this->ot['msg'] && $found ) {
                        if ( $noargs ) {
                                $assocArgs = array();
                        } else {
@@ -2998,16 +3077,20 @@ class Parser
                                $text = preg_replace( '/<noinclude>.*?<\/noinclude>/s', '', $text );
                                $text = strtr( $text, array( '<includeonly>' => '' , '</includeonly>' => '' ) );
 
-                               if( $this->mOutputType == OT_HTML ) {
+                               if( $this->ot['html'] || $this->ot['pre'] ) {
                                        # Strip <nowiki>, <pre>, etc.
                                        $text = $this->strip( $text, $this->mStripState );
-                                       $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs );
+                                       if ( $this->ot['html'] ) {
+                                               $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs );
+                                       } elseif ( $this->ot['pre'] && $this->mOptions->getRemoveComments() ) {
+                                               $text = Sanitizer::removeHTMLcomments( $text );
+                                       }
                                }
                                $text = $this->replaceVariables( $text, $assocArgs );
 
                                # If the template begins with a table or block-level
                                # element, it should be treated as beginning a new line.
-                               if (!$piece['lineStart'] && preg_match('/^({\\||:|;|#|\*)/', $text)) {
+                               if (!$piece['lineStart'] && preg_match('/^({\\||:|;|#|\*)/', $text)) /*}*/{ 
                                        $text = "\n" . $text;
                                }
                        } elseif ( !$noargs ) {
@@ -3023,8 +3106,7 @@ class Parser
                if ( $found && !$this->incrementIncludeSize( 'post-expand', strlen( $text ) ) ) {
                        # Error, oversize inclusion
                        $text = $linestart .
-                               '{{' . $part1 . '}}' .
-                               '<!-- WARNING: template omitted, post-expand include size too large -->';
+                               "[[$titleText]]<!-- WARNING: template omitted, post-expand include size too large -->";
                        $noparse = true;
                        $noargs = true;
                }
@@ -3042,7 +3124,7 @@ class Parser
                        } else {
                                # replace ==section headers==
                                # XXX this needs to go away once we have a better parser.
-                               if ( $this->mOutputType != OT_WIKI && $replaceHeadings ) {
+                               if ( !$this->ot['wiki'] && !$this->ot['pre'] && $replaceHeadings ) {
                                        if( !is_null( $title ) )
                                                $encodedname = base64_encode($title->getPrefixedDBkey());
                                        else
@@ -3166,7 +3248,8 @@ class Parser
 
                if ( array_key_exists( $arg, $inputArgs ) ) {
                        $text = $inputArgs[$arg];
-               } else if ($this->mOutputType == OT_HTML && null != $matches['parts'] && count($matches['parts']) > 0) {
+               } else if (($this->mOutputType == OT_HTML || $this->mOutputType == OT_PREPROCESS ) && 
+               null != $matches['parts'] && count($matches['parts']) > 0) {
                        $text = $matches['parts'][0];
                }
                if ( !$this->incrementIncludeSize( 'arg', strlen( $text ) ) ) {
@@ -3496,7 +3579,7 @@ class Parser
        function preSaveTransform( $text, &$title, &$user, $options, $clearState = true ) {
                $this->mOptions = $options;
                $this->mTitle =& $title;
-               $this->mOutputType = OT_WIKI;
+               $this->setOutputType( OT_WIKI );
 
                if ( $clearState ) {
                        $this->clearState();
@@ -3669,7 +3752,7 @@ class Parser
        function startExternalParse( &$title, $options, $outputType, $clearState = true ) {
                $this->mTitle =& $title;
                $this->mOptions = $options;
-               $this->mOutputType = $outputType;
+               $this->setOutputType( $outputType );
                if ( $clearState ) {
                        $this->clearState();
                }
@@ -3699,7 +3782,7 @@ class Parser
 
                $this->mTitle = $wgTitle;
                $this->mOptions = $options;
-               $this->mOutputType = OT_MSG;
+               $this->setOutputType( OT_MSG );
                $this->clearState();
                $text = $this->replaceVariables( $text );
 
@@ -3761,10 +3844,8 @@ class Parser
 
                # Add to function cache
                $mw = MagicWord::get( $id );
-               if ( !$mw ) {
-                       throw new MWException( 'The calling convention to Parser::setFunctionHook() has changed, ' .
-                               'it is now required to pass a MagicWord ID as the first parameter.' );
-               }
+               if( !$mw )
+                       throw new MWException( 'Parser::setFunctionHook() expecting a magic word identifier.' );
 
                $synonyms = $mw->getSynonyms();
                $sensitive = intval( $mw->isCaseSensitive() );
@@ -3787,6 +3868,15 @@ class Parser
                return $oldVal;
        }
 
+       /**
+        * Get all registered function hook identifiers
+        *
+        * @return array
+        */
+       function getFunctionHooks() {
+               return array_keys( $this->mFunctionHooks );
+       }
+
        /**
         * Replace <!--LINK--> link placeholders with actual links, in the buffer
         * Placeholders created in Skin::makeLinkObj()
@@ -3799,6 +3889,7 @@ class Parser
        function replaceLinkHolders( &$text, $options = 0 ) {
                global $wgUser;
                global $wgOutputReplace;
+               global $wgContLang, $wgLanguageCode;
 
                $fname = 'Parser::replaceLinkHolders';
                wfProfileIn( $fname );
@@ -3889,6 +3980,91 @@ class Parser
                        }
                        wfProfileOut( $fname.'-check' );
 
+                       # Do a second query for different language variants of links (if needed)
+                       if($wgContLang->hasVariants()){
+                               $linkBatch = new LinkBatch(); 
+                               $variantMap = array(); // maps $pdbkey_Variant => $pdbkey_original
+
+                               // Add variants of links to link batch
+                               foreach ( $this->mLinkHolders['namespaces'] as $key => $ns ) {
+                                       $title = $this->mLinkHolders['titles'][$key];
+                                       if ( is_null( $title ) )
+                                               continue;
+
+                                       $pdbk = $title->getPrefixedDBkey();
+
+                                       // generate all variants of the link title text
+                                       $allTextVariants = $wgContLang->convertLinkToAllVariants($title->getText());
+
+                                       // if link was not found (in first query), add all variants to query
+                                       if ( !isset($colours[$pdbk]) ){
+                                               foreach($allTextVariants as $textVariant){
+                                                       $variantTitle = Title::makeTitle( $ns, $textVariant );
+                                                       if(is_null($variantTitle)) continue;
+                                                       $linkBatch->addObj( $variantTitle );
+                                                       $variantMap[$variantTitle->getPrefixedDBkey()][] = $key;
+                                               }
+                                       }
+                               }
+                               
+
+                               if(!$linkBatch->isEmpty()){
+                                       // construct query
+                                       $titleClause = $linkBatch->constructSet('page', $dbr);
+
+                                       $variantQuery =  "SELECT page_id, page_namespace, page_title";
+                                       if ( $threshold > 0 ) {
+                                               $variantQuery .= ', page_len, page_is_redirect';
+                                       }
+
+                                       $variantQuery .= " FROM $page WHERE $titleClause";
+                                       if ( $options & RLH_FOR_UPDATE ) {
+                                               $variantQuery .= ' FOR UPDATE';
+                                       }
+
+                                       $varRes = $dbr->query( $variantQuery, $fname );
+
+                                       // for each found variants, figure out link holders and replace
+                                       while ( $s = $dbr->fetchObject($varRes) ) {
+
+                                               $variantTitle = Title::makeTitle( $s->page_namespace, $s->page_title );
+                                               $varPdbk = $variantTitle->getPrefixedDBkey();
+                                               $linkCache->addGoodLinkObj( $s->page_id, $variantTitle );
+                                               $this->mOutput->addLink( $variantTitle, $s->page_id );
+
+                                               $holderKeys = $variantMap[$varPdbk];
+
+                                               // loop over link holders
+                                               foreach($holderKeys as $key){                                           
+                                                       $title = $this->mLinkHolders['titles'][$key];
+                                                       if ( is_null( $title ) ) continue;
+
+                                                       $pdbk = $title->getPrefixedDBkey();
+
+                                                       if(!isset($colours[$pdbk])){
+                                                               // found link in some of the variants, replace the link holder data
+                                                               $this->mLinkHolders['titles'][$key] = $variantTitle;
+                                                               $this->mLinkHolders['dbkeys'][$key] = $variantTitle->getDBkey();
+                                                       
+                                                               // set pdbk and colour
+                                                               $pdbks[$key] = $varPdbk;
+                                                               if ( $threshold >  0 ) {
+                                                                       $size = $s->page_len;
+                                                                       if ( $s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold ) {
+                                                                               $colours[$varPdbk] = 1;
+                                                                       } else {
+                                                                               $colours[$varPdbk] = 2;
+                                                                       }
+                                                               } 
+                                                               else {
+                                                                       $colours[$varPdbk] = 1;
+                                                               }                                       
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
                        # Construct search and replace arrays
                        wfProfileIn( $fname.'-construct' );
                        $wgOutputReplace = array();
@@ -4062,7 +4238,7 @@ class Parser
         * Parse image options text and use it to make an image
         */
        function makeImage( &$nt, $options ) {
-               global $wgUseImageResize;
+               global $wgUseImageResize, $wgDjvuRenderer;
 
                $align = '';
 
@@ -4100,9 +4276,6 @@ class Parser
                                # use manually specified thumbnail
                                $thumb=true;
                                $manual_thumb = $match;
-                       } elseif ( ! is_null( $match = $mwPage->matchVariableStartToEnd($val) ) ) {
-                               # Select a page in a multipage document
-                               $page = $match;
                        } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
                                # remember to set an alignment, don't render immediately
                                $align = 'right';
@@ -4115,6 +4288,10 @@ class Parser
                        } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) {
                                # remember to set an alignment, don't render immediately
                                $align = 'none';
+                       } elseif ( isset( $wgDjvuRenderer ) && $wgDjvuRenderer
+                                  && ! is_null( $match = $mwPage->matchVariableStartToEnd($val) ) ) {
+                               # Select a page in a multipage document
+                               $page = $match;
                        } elseif ( $wgUseImageResize && ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) {
                                wfDebug( "img_width match: $match\n" );
                                # $match is the image width in pixels
@@ -4141,8 +4318,7 @@ class Parser
 
                # Linker does the rest
                $sk =& $this->mOptions->getSkin();
-               return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height,
-                               $framed, $thumb, $manual_thumb, $page );
+               return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb, $page );
        }
 
        /**
@@ -4213,11 +4389,11 @@ class Parser
                $oldOutputType = $this->mOutputType;
                $oldOptions = $this->mOptions;
                $this->mOptions = new ParserOptions();
-               $this->mOutputType = OT_WIKI;
+               $this->setOutputType( OT_WIKI );
 
                $striptext = $this->strip( $text, $striparray, true );
 
-               $this->mOutputType = $oldOutputType;
+               $this->setOutputType( $oldOutputType );
                $this->mOptions = $oldOptions;
 
                # now that we can be sure that no pseudo-sections are in the source,
@@ -4425,12 +4601,15 @@ class ParserOutput
                return (bool)$this->mNewSection;
        }
 
-       function addLink( $title, $id ) {
+       function addLink( $title, $id = null ) {
                $ns = $title->getNamespace();
                $dbk = $title->getDBkey();
                if ( !isset( $this->mLinks[$ns] ) ) {
                        $this->mLinks[$ns] = array();
                }
+               if ( is_null( $id ) ) {
+                       $id = $title->getArticleID();
+               }
                $this->mLinks[$ns][$dbk] = $id;
        }
 
@@ -4483,6 +4662,7 @@ class ParserOptions
        var $mTidy;                      # Ask for tidy cleanup
        var $mInterfaceMessage;          # Which lang to call for PLURAL and GRAMMAR
        var $mMaxIncludeSize;            # Maximum size of template expansions, in bytes
+       var $mRemoveComments;            # Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
 
        var $mUser;                      # Stored user object, just used to initialise the skin
 
@@ -4497,6 +4677,7 @@ class ParserOptions
        function getTidy()                          { return $this->mTidy; }
        function getInterfaceMessage()              { return $this->mInterfaceMessage; }
        function getMaxIncludeSize()                { return $this->mMaxIncludeSize; }
+       function getRemoveComments()                { return $this->mRemoveComments; }
 
        function &getSkin() {
                if ( !isset( $this->mSkin ) ) {
@@ -4525,6 +4706,7 @@ class ParserOptions
        function setSkin( &$x ) { $this->mSkin =& $x; }
        function setInterfaceMessage( $x )          { return wfSetVar( $this->mInterfaceMessage, $x); }
        function setMaxIncludeSize( $x )            { return wfSetVar( $this->mMaxIncludeSize, $x ); }
+       function setRemoveComments( $x )            { return wfSetVar( $this->mRemoveComments, $x ); }
 
        function ParserOptions( $user = null ) {
                $this->initialiseFromUser( $user );
@@ -4571,6 +4753,7 @@ class ParserOptions
                $this->mTidy = false;
                $this->mInterfaceMessage = false;
                $this->mMaxIncludeSize = $wgMaxArticleSize * 1024;
+               $this->mRemoveComments = true;
                wfProfileOut( $fname );
        }
 }