<?php
/**
* File for magic words
+ *
* See docs/magicword.txt
*
* @file
'numberofarticles',
'numberoffiles',
'numberofedits',
+ 'articlepath',
'sitename',
'server',
'servername',
'scriptpath',
+ 'stylepath',
'pagename',
'pagenamee',
'fullpagename',
'revisionday',
'revisionday2',
'revisionmonth',
+ 'revisionmonth1',
'revisionyear',
'revisiontimestamp',
'revisionuser',
/* Array of caching hints for ParserCache */
static public $mCacheTTLs = array (
- 'currentmonth' => 86400,
- 'currentmonth1' => 86400,
- 'currentmonthname' => 86400,
- 'currentmonthnamegen' => 86400,
- 'currentmonthabbrev' => 86400,
- 'currentday' => 3600,
- 'currentday2' => 3600,
- 'currentdayname' => 3600,
- 'currentyear' => 86400,
- 'currenttime' => 3600,
- 'currenthour' => 3600,
- 'localmonth' => 86400,
- 'localmonth1' => 86400,
- 'localmonthname' => 86400,
- 'localmonthnamegen' => 86400,
- 'localmonthabbrev' => 86400,
- 'localday' => 3600,
- 'localday2' => 3600,
- 'localdayname' => 3600,
- 'localyear' => 86400,
- 'localtime' => 3600,
- 'localhour' => 3600,
- 'numberofarticles' => 3600,
- 'numberoffiles' => 3600,
- 'numberofedits' => 3600,
- 'currentweek' => 3600,
- 'currentdow' => 3600,
- 'localweek' => 3600,
- 'localdow' => 3600,
- 'numberofusers' => 3600,
- 'numberofactiveusers' => 3600,
- 'numberofpages' => 3600,
- 'currentversion' => 86400,
- 'currenttimestamp' => 3600,
- 'localtimestamp' => 3600,
- 'pagesinnamespace' => 3600,
- 'numberofadmins' => 3600,
- 'numberofviews' => 3600,
- 'numberingroup' => 3600,
- 'numberofcontribs' => 3600,
+ 'currentmonth' => 86400,
+ 'currentmonth1' => 86400,
+ 'currentmonthname' => 86400,
+ 'currentmonthnamegen' => 86400,
+ 'currentmonthabbrev' => 86400,
+ 'currentday' => 3600,
+ 'currentday2' => 3600,
+ 'currentdayname' => 3600,
+ 'currentyear' => 86400,
+ 'currenttime' => 3600,
+ 'currenthour' => 3600,
+ 'localmonth' => 86400,
+ 'localmonth1' => 86400,
+ 'localmonthname' => 86400,
+ 'localmonthnamegen' => 86400,
+ 'localmonthabbrev' => 86400,
+ 'localday' => 3600,
+ 'localday2' => 3600,
+ 'localdayname' => 3600,
+ 'localyear' => 86400,
+ 'localtime' => 3600,
+ 'localhour' => 3600,
+ 'numberofarticles' => 3600,
+ 'numberoffiles' => 3600,
+ 'numberofedits' => 3600,
+ 'currentweek' => 3600,
+ 'currentdow' => 3600,
+ 'localweek' => 3600,
+ 'localdow' => 3600,
+ 'numberofusers' => 3600,
+ 'numberofactiveusers' => 3600,
+ 'numberofpages' => 3600,
+ 'currentversion' => 86400,
+ 'currenttimestamp' => 3600,
+ 'localtimestamp' => 3600,
+ 'pagesinnamespace' => 3600,
+ 'numberofadmins' => 3600,
+ 'numberofviews' => 3600,
+ 'numberingroup' => 3600,
);
static public $mDoubleUnderscoreIDs = array(
'index',
'noindex',
'staticredirect',
+ 'notitleconvert',
+ 'nocontentconvert',
);
+ static public $mSubstIDs = array(
+ 'subst',
+ 'safesubst',
+ );
static public $mObjects = array();
static public $mDoubleUnderscoreArray = null;
/**#@-*/
- function __construct($id = 0, $syn = '', $cs = false) {
+ function __construct($id = 0, $syn = array(), $cs = false) {
$this->mId = $id;
$this->mSynonyms = (array)$syn;
$this->mCaseSensitive = $cs;
/**
* Factory: creates an object representing an ID
* @static
+ * @return MagicWord
*/
static function &get( $id ) {
wfProfileIn( __METHOD__ );
- if (!array_key_exists( $id, self::$mObjects ) ) {
+ if ( !isset( self::$mObjects[$id] ) ) {
$mw = new MagicWord();
$mw->load( $id );
self::$mObjects[$id] = $mw;
return self::$mVariableIDs;
}
+ /**
+ * Get an array of parser substitution modifier IDs
+ */
+ static function getSubstIDs() {
+ return self::$mSubstIDs;
+ }
+
/* Allow external reads of TTL array */
static function getCacheTTL($id) {
if (array_key_exists($id,self::$mCacheTTLs)) {
return self::$mDoubleUnderscoreArray;
}
+ /**
+ * Clear the self::$mObjects variable
+ * For use in parser tests
+ */
+ public static function clearCache() {
+ self::$mObjects = array();
+ }
+
# Initialises this object with an ID
function load( $id ) {
global $wgContLang;
* @private
*/
function initRegex() {
- #$variableClass = Title::legalChars();
- # This was used for matching "$1" variables, but different uses of the feature will have
- # different restrictions, which should be checked *after* the MagicWord has been matched,
- # not here. - IMSoP
+ // Sort the synonyms by length, descending, so that the longest synonym
+ // matches in precedence to the shortest
+ $synonyms = $this->mSynonyms;
+ usort( $synonyms, array( $this, 'compareStringLength' ) );
$escSyn = array();
- foreach ( $this->mSynonyms as $synonym )
+ foreach ( $synonyms as $synonym )
// In case a magic word contains /, like that's going to happen;)
$escSyn[] = preg_quote( $synonym, '/' );
$this->mBaseRegex = implode( '|', $escSyn );
"/^(?:{$this->mBaseRegex})$/{$case}" );
}
+ /**
+ * A comparison function that returns -1, 0 or 1 depending on whether the
+ * first string is longer, the same length or shorter than the second
+ * string.
+ */
+ function compareStringLength( $s1, $s2 ) {
+ $l1 = strlen( $s1 );
+ $l2 = strlen( $s2 );
+ if ( $l1 < $l2 ) {
+ return 1;
+ } elseif ( $l1 > $l2 ) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
/**
* Gets a regex representing matching the word
*/
* @return bool
*/
function match( $text ) {
- return preg_match( $this->getRegex(), $text );
+ return (bool)preg_match( $this->getRegex(), $text );
}
/**
* @return bool
*/
function matchStart( $text ) {
- return preg_match( $this->getRegexStart(), $text );
+ return (bool)preg_match( $this->getRegexStart(), $text );
}
/**
$matches = array();
$matchcount = preg_match( $this->getVariableStartToEndRegex(), $text, $matches );
if ( $matchcount == 0 ) {
- return NULL;
+ return null;
} else {
# multiple matched parts (variable match); some will be empty because of
# synonyms. The variable will be the second non-empty one so remove any
* Add a magic word by name
*/
public function add( $name ) {
- global $wgContLang;
$this->names[] = $name;
$this->hash = $this->baseRegex = $this->regex = null;
}
}
/**
- * Get an unanchored regex
+ * Get an unanchored regex that does not match parameters
*/
function getRegex() {
if ( is_null( $this->regex ) ) {
}
/**
- * Get a regex for matching variables
+ * Get a regex for matching variables with parameters
*/
function getVariableRegex() {
return str_replace( "\\$1", "(.*?)", $this->getRegex() );
}
/**
- * Get an anchored regex for matching variables
+ * Get a regex anchored to the start of the string that does not match parameters
+ */
+ function getRegexStart() {
+ $base = $this->getBaseRegex();
+ $newRegex = array( '', '' );
+ if ( $base[0] !== '' ) {
+ $newRegex[0] = "/^(?:{$base[0]})/iuS";
+ }
+ if ( $base[1] !== '' ) {
+ $newRegex[1] = "/^(?:{$base[1]})/S";
+ }
+ return $newRegex;
+ }
+
+ /**
+ * Get an anchored regex for matching variables with parameters
*/
function getVariableStartToEndRegex() {
$base = $this->getBaseRegex();
}
// This shouldn't happen either
throw new MWException( __METHOD__.': parameter not found' );
- return array( false, false );
}
/**
* Both elements are false if there was no match.
*/
public function matchVariableStartToEnd( $text ) {
- global $wgContLang;
$regexes = $this->getVariableStartToEndRegex();
foreach ( $regexes as $regex ) {
if ( $regex !== '' ) {
}
return $found;
}
+
+ /**
+ * Return the ID of the magic word at the start of $text, and remove
+ * the prefix from $text.
+ * Return false if no match found and $text is not modified.
+ * Does not match parameters.
+ */
+ public function matchStartAndRemove( &$text ) {
+ $regexes = $this->getRegexStart();
+ foreach ( $regexes as $regex ) {
+ if ( $regex === '' ) {
+ continue;
+ }
+ if ( preg_match( $regex, $text, $m ) ) {
+ list( $id, ) = $this->parseMatch( $m );
+ if ( strlen( $m[0] ) >= strlen( $text ) ) {
+ $text = '';
+ } else {
+ $text = substr( $text, strlen( $m[0] ) );
+ }
+ return $id;
+ }
+ }
+ return false;
+ }
}