r39618 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r39617‎ | r39618 | r39619 >
Date:22:19, 18 August 2008
Author:krimpet
Status:old
Tags:
Comment:
Per discussion for bug 6455, merged functionality of StringFunctions into the ParserFunctions extension.
Modified paths:
  • /trunk/extensions/ParserFunctions/ParserFunctions.i18n.magic.php (modified) (history)
  • /trunk/extensions/ParserFunctions/ParserFunctions.php (modified) (history)

Diff [purge]

Index: trunk/extensions/ParserFunctions/ParserFunctions.i18n.magic.php
@@ -25,6 +25,16 @@
2626 'timel' => array( 0, 'timel' ),
2727 'rel2abs' => array( 0, 'rel2abs' ),
2828 'titleparts' => array( 0, 'titleparts' ),
 29+
 30+ 'len' => array( 0, 'len' ),
 31+ 'pos' => array( 0, 'pos' ),
 32+ 'rpos' => array( 0, 'rpos' ),
 33+ 'sub' => array( 0, 'sub' ),
 34+ 'pad' => array( 0, 'pad' ),
 35+ 'replace' => array( 0, 'replace' ),
 36+ 'explode' => array( 0, 'explode' ),
 37+ 'urlencode' => array( 0, 'urlencode' ),
 38+ 'urldecode' => array( 0, 'urldecode' ),
2939 );
3040
3141 /**
Index: trunk/extensions/ParserFunctions/ParserFunctions.php
@@ -7,9 +7,9 @@
88 $wgExtensionFunctions[] = 'wfSetupParserFunctions';
99 $wgExtensionCredits['parserhook'][] = array(
1010 'name' => 'ParserFunctions',
11 - 'version' => '1.1.1',
 11+ 'version' => '2.0',
1212 'url' => 'http://meta.wikimedia.org/wiki/ParserFunctions',
13 - 'author' => 'Tim Starling',
 13+ 'author' => array('Tim Starling', 'Ross McClure', 'Juraj Simlovic', 'Fran Rogers'),
1414 'description' => 'Enhance parser with logical functions',
1515 'descriptionmsg' => 'pfunc_desc',
1616 );
@@ -17,6 +17,10 @@
1818 $wgExtensionMessagesFiles['ParserFunctions'] = dirname(__FILE__) . '/ParserFunctions.i18n.php';
1919 $wgHooks['LanguageGetMagic'][] = 'wfParserFunctionsLanguageGetMagic';
2020
 21+$wgStringFunctionsLimitSearch = 30;
 22+$wgStringFunctionsLimitReplace = 30;
 23+$wgStringFunctionsLimitPad = 100;
 24+
2125 class ExtParserFunctions {
2226 var $mExprParser;
2327 var $mTimeCache = array();
@@ -47,6 +51,16 @@
4852 $parser->setFunctionHook( 'rel2abs', array( &$this, 'rel2abs' ) );
4953 $parser->setFunctionHook( 'titleparts', array( &$this, 'titleparts' ) );
5054
 55+ $parser->setFunctionHook( 'len', array( &$this, 'len' ) );
 56+ $parser->setFunctionHook( 'pos', array( &$this, 'pos' ) );
 57+ $parser->setFunctionHook( 'rpos', array( &$this, 'rpos' ) );
 58+ $parser->setFunctionHook( 'sub', array( &$this, 'sub' ) );
 59+ $parser->setFunctionHook( 'pad', array( &$this, 'pad' ) );
 60+ $parser->setFunctionHook( 'replace', array( &$this, 'replace' ) );
 61+ $parser->setFunctionHook( 'explode', array( &$this, 'explode' ) );
 62+ $parser->setFunctionHook( 'urlencode', array( &$this, 'urlencode' ) );
 63+ $parser->setFunctionHook( 'urldecode', array( &$this, 'urldecode' ) );
 64+
5165 return true;
5266 }
5367
@@ -476,6 +490,294 @@
477491 return $title;
478492 }
479493 }
 494+
 495+ /**
 496+ * Splits the string into its component parts using preg_match_all().
 497+ * $chars is set to the resulting array of multibyte characters.
 498+ * Returns count($chars).
 499+ */
 500+ function mwSplit ( &$parser, $str, &$chars ) {
 501+ # Get marker prefix & suffix
 502+ $prefix = preg_quote( $parser->mUniqPrefix );
 503+ if( isset($parser->mMarkerSuffix) )
 504+ $suffix = preg_quote( $parser->mMarkerSuffix );
 505+ else if ( strcmp( MW_PARSER_VERSION, '1.6.1' ) > 0 )
 506+ $suffix = 'QINU\x07';
 507+ else $suffix = 'QINU';
 508+
 509+ # Treat strip markers as single multibyte characters
 510+ $count = preg_match_all('/' . $prefix . '.*?' . $suffix . '|./su', $str, $arr);
 511+ $chars = $arr[0];
 512+ return $count;
 513+ }
 514+
 515+ /**
 516+ * {{#len:value}}
 517+ */
 518+ function len( &$parser, $inStr = '' ) {
 519+ return $this->mwSplit ( $parser, $inStr, $chars );
 520+ }
 521+
 522+ /**
 523+ * {{#pos:value|key|offset}}
 524+ * Note: If the needle is an empty string, single space is used instead.
 525+ * Note: If the needle is not found, empty string is returned.
 526+ * Note: The needle is limited to specific length.
 527+ */
 528+ function pos( &$parser, $inStr = '', $inNeedle = '', $inOffset = 0 ) {
 529+ global $wgStringFunctionsLimitSearch;
 530+
 531+ if ( $inNeedle === '' ) {
 532+ # empty needle
 533+ $needle = array(' ');
 534+ $nSize = 1;
 535+ } else {
 536+ # convert needle
 537+ $nSize = $this->mwSplit ( $parser, $inNeedle, $needle );
 538+
 539+ if ( $nSize > $wgStringFunctionsLimitSearch ) {
 540+ $nSize = $wgStringFunctionsLimitSearch;
 541+ $needle = array_slice ( $needle, 0, $nSize );
 542+ }
 543+ }
 544+
 545+ # convert string
 546+ $size = $this->mwSplit( $parser, $inStr, $chars ) - $nSize;
 547+ $inOffset = max ( intval($inOffset), 0 );
 548+
 549+ # find needle
 550+ for ( $i = $inOffset; $i <= $size; $i++ ) {
 551+ if ( $chars[$i] !== $needle[0] ) continue;
 552+ for ( $j = 1; ; $j++ ) {
 553+ if ( $j >= $nSize ) return $i;
 554+ if ( $chars[$i + $j] !== $needle[$j] ) break;
 555+ }
 556+ }
 557+
 558+ # return empty string upon not found
 559+ return '';
 560+ }
 561+
 562+ /**
 563+ * {{#rpos:value|key}}
 564+ * Note: If the needle is an empty string, single space is used instead.
 565+ * Note: If the needle is not found, -1 is returned.
 566+ * Note: The needle is limited to specific length.
 567+ */
 568+ function rPos( &$parser, $inStr = '', $inNeedle = '' ) {
 569+ global $wgStringFunctionsLimitSearch;
 570+
 571+ if ( $inNeedle === '' ) {
 572+ # empty needle
 573+ $needle = array(' ');
 574+ $nSize = 1;
 575+ } else {
 576+ # convert needle
 577+ $nSize = $this->mwSplit ( $parser, $inNeedle, $needle );
 578+
 579+ if ( $nSize > $wgStringFunctionsLimitSearch ) {
 580+ $nSize = $wgStringFunctionsLimitSearch;
 581+ $needle = array_slice ( $needle, 0, $nSize );
 582+ }
 583+ }
 584+
 585+ # convert string
 586+ $size = $this->mwSplit( $parser, $inStr, $chars ) - $nSize;
 587+
 588+ # find needle
 589+ for ( $i = $size; $i >= 0; $i-- ) {
 590+ if ( $chars[$i] !== $needle[0] ) continue;
 591+ for ( $j = 1; ; $j++ ) {
 592+ if ( $j >= $nSize ) return $i;
 593+ if ( $chars[$i + $j] !== $needle[$j] ) break;
 594+ }
 595+ }
 596+
 597+ # return -1 upon not found
 598+ return "-1";
 599+ }
 600+
 601+ /**
 602+ * {{#sub:value|start|length}}
 603+ * Note: If length is zero, the rest of the input is returned.
 604+ */
 605+ function sub( &$parser, $inStr = '', $inStart = 0, $inLength = 0 ) {
 606+ # convert string
 607+ $this->mwSplit( $parser, $inStr, $chars );
 608+
 609+ # zero length
 610+ if ( intval($inLength) == 0 )
 611+ return join('', array_slice( $chars, intval($inStart) ));
 612+
 613+ # non-zero length
 614+ return join('', array_slice( $chars, intval($inStart), intval($inLength) ));
 615+ }
 616+
 617+ /**
 618+ * {{#pad:value|length|with|direction}}
 619+ * Note: Length of the resulting string is limited.
 620+ */
 621+ function pad( &$parser, $inStr = '', $inLen = 0, $inWith = '', $inDirection = '' ) {
 622+ global $wgStringFunctionsLimitPad;
 623+
 624+ # direction
 625+ switch ( strtolower ( $inDirection ) ) {
 626+ case 'center':
 627+ $direction = STR_PAD_BOTH;
 628+ break;
 629+ case 'right':
 630+ $direction = STR_PAD_RIGHT;
 631+ break;
 632+ case 'left':
 633+ default:
 634+ $direction = STR_PAD_LEFT;
 635+ break;
 636+ }
 637+
 638+ # prevent markers in padding
 639+ $a = explode ( $parser->mUniqPrefix, $inWith, 2 );
 640+ if ( $a[0] === '' )
 641+ $inWith = ' ';
 642+ else $inWith = $a[0];
 643+
 644+ # limit pad length
 645+ $inLen = intval ( $inLen );
 646+ if ($wgStringFunctionsLimitPad > 0)
 647+ $inLen = min ( $inLen, $wgStringFunctionsLimitPad );
 648+
 649+ # adjust for multibyte strings
 650+ $inLen += strlen( $inStr ) - $this->mwSplit( $parser, $inStr, $a );
 651+
 652+ # pad
 653+ return str_pad ( $inStr, $inLen, $inWith, $direction );
 654+ }
 655+
 656+ /**
 657+ * {{#replace:value|from|to}}
 658+ * Note: If the needle is an empty string, single space is used instead.
 659+ * Note: The needle is limited to specific length.
 660+ * Note: The product is limited to specific length.
 661+ */
 662+ function replace( &$parser, $inStr = '', $inReplaceFrom = '', $inReplaceTo = '' ) {
 663+ global $wgStringFunctionsLimitSearch, $wgStringFunctionsLimitReplace;
 664+
 665+ if ( $inReplaceFrom === '' ) {
 666+ # empty needle
 667+ $needle = array(' ');
 668+ $nSize = 1;
 669+ } else {
 670+ # convert needle
 671+ $nSize = $this->mwSplit ( $parser, $inReplaceFrom, $needle );
 672+ if ( $nSize > $wgStringFunctionsLimitSearch ) {
 673+ $nSize = $wgStringFunctionsLimitSearch;
 674+ $needle = array_slice ( $needle, 0, $nSize );
 675+ }
 676+ }
 677+
 678+ # convert product
 679+ $pSize = $this->mwSplit ( $parser, $inReplaceTo, $product );
 680+ if ( $pSize > $wgStringFunctionsLimitReplace ) {
 681+ $pSize = $wgStringFunctionsLimitReplace;
 682+ $product = array_slice ( $product, 0, $pSize );
 683+ }
 684+
 685+ # remove markers in product
 686+ for( $i = 0; $i < $pSize; $i++ ) {
 687+ if( strlen( $product[$i] ) > 6 ) $product[$i] = ' ';
 688+ }
 689+
 690+ # convert string
 691+ $size = $this->mwSplit ( $parser, $inStr, $chars ) - $nSize;
 692+
 693+ # replace
 694+ for ( $i = 0; $i <= $size; $i++ ) {
 695+ if ( $chars[$i] !== $needle[0] ) continue;
 696+ for ( $j = 1; ; $j++ ) {
 697+ if ( $j >= $nSize ) {
 698+ array_splice ( $chars, $i, $j, $product );
 699+ $size += ( $pSize - $nSize );
 700+ $i += ( $pSize - 1 );
 701+ break;
 702+ }
 703+ if ( $chars[$i + $j] !== $needle[$j] ) break;
 704+ }
 705+ }
 706+ return join('', $chars);
 707+ }
 708+
 709+ /**
 710+ * {{#explode:value|delimiter|position}}
 711+ * Note: Negative position can be used to specify tokens from the end.
 712+ * Note: If the divider is an empty string, single space is used instead.
 713+ * Note: The divider is limited to specific length.
 714+ * Note: Empty string is returned, if there is not enough exploded chunks.
 715+ */
 716+ function explode( &$parser, $inStr = '', $inDiv = '', $inPos = 0 ) {
 717+ global $wgStringFunctionsLimitSearch;
 718+
 719+ if ( $inDiv === '' ) {
 720+ # empty divider
 721+ $div = array(' ');
 722+ $dSize = 1;
 723+ } else {
 724+ # convert divider
 725+ $dSize = $this->mwSplit ( $parser, $inDiv, $div );
 726+ if ( $dSize > $wgStringFunctionsLimitSearch ) {
 727+ $dSize = $wgStringFunctionsLimitSearch;
 728+ $div = array_slice ( $div, 0, $dSize );
 729+ }
 730+ }
 731+
 732+ # convert string
 733+ $size = $this->mwSplit ( $parser, $inStr, $chars ) - $dSize;
 734+
 735+ # explode
 736+ $inPos = intval ( $inPos );
 737+ $tokens = array();
 738+ $start = 0;
 739+ for ( $i = 0; $i <= $size; $i++ ) {
 740+ if ( $chars[$i] !== $div[0] ) continue;
 741+ for ( $j = 1; ; $j++ ) {
 742+ if ( $j >= $dSize ) {
 743+ if ( $inPos > 0 ) $inPos--;
 744+ else {
 745+ $tokens[] = join('', array_slice($chars, $start, ($i - $start)));
 746+ if ( $inPos == 0 ) return $tokens[0];
 747+ }
 748+ $start = $i + $j;
 749+ $i = $start - 1;
 750+ break;
 751+ }
 752+ if ( $chars[$i + $j] !== $div[$j] ) break;
 753+ }
 754+ }
 755+ $tokens[] = join('', array_slice( $chars, $start ));
 756+
 757+ # negative $inPos
 758+ if ( $inPos < 0 ) $inPos += count ( $tokens );
 759+
 760+ # out of range
 761+ if ( !isset ( $tokens[$inPos] ) ) return "";
 762+
 763+ # in range
 764+ return $tokens[$inPos];
 765+ }
 766+
 767+ /**
 768+ * {{#urlencode:value}}
 769+ */
 770+ function urlEncode ( &$parser, $inStr = '' ) {
 771+ # encode
 772+ return urlencode ( $inStr );
 773+ }
 774+
 775+ /**
 776+ * {{#urldecode:value}}
 777+ */
 778+ function urlDecode ( &$parser, $inStr = '' ) {
 779+ # decode
 780+ return urldecode ( $inStr );
 781+ }
480782 }
481783
482784 function wfSetupParserFunctions() {
@@ -502,4 +804,3 @@
503805 $magicWords[$word] = $trans;
504806 return true;
505807 }
506 -

Follow-up revisions

RevisionCommit summaryAuthorDate
r39653Revert r39618 "Per discussion for bug 6455, merged functionality of StringFun...brion18:53, 19 August 2008
r49043Adds fallback implementations of mb_strpos and mb_strrpos if native multi-byt...rarohde19:11, 30 March 2009
r50997(Bug 6455) Add string function support to ParserFunctionsrarohde00:43, 26 May 2009

Status & tagging log