Merge "Drop index oi_name_archive_name on table oldimage"
[lhc/web/wiklou.git] / includes / parser / BlockLevelPass.php
index cbacd34..2023d13 100644 (file)
@@ -38,6 +38,7 @@ class BlockLevelPass {
        const COLON_STATE_COMMENT = 5;
        const COLON_STATE_COMMENTDASH = 6;
        const COLON_STATE_COMMENTDASHDASH = 7;
+       const COLON_STATE_LC = 8;
 
        /**
         * Make lists from lines starting with ':', '*', '#', etc.
@@ -298,7 +299,7 @@ class BlockLevelPass {
 
                                if ( $openMatch || $closeMatch ) {
                                        $pendingPTag = false;
-                                       # @todo bug 5718: paragraph closed
+                                       # @todo T7718: paragraph closed
                                        $output .= $this->closeParagraph();
                                        if ( $preOpenMatch && !$preCloseMatch ) {
                                                $this->inPre = true;
@@ -352,7 +353,7 @@ class BlockLevelPass {
                                        }
                                }
                        }
-                       # somewhere above we forget to get out of pre block (bug 785)
+                       # somewhere above we forget to get out of pre block (T2785)
                        if ( $preCloseMatch && $this->inPre ) {
                                $this->inPre = false;
                        }
@@ -389,15 +390,14 @@ class BlockLevelPass {
         * @return string The position of the ':', or false if none found
         */
        private function findColonNoLinks( $str, &$before, &$after ) {
-               $colonPos = strpos( $str, ':' );
-               if ( $colonPos === false ) {
+               if ( !preg_match( '/:|<|-\{/', $str, $m, PREG_OFFSET_CAPTURE ) ) {
                        # Nothing to find!
                        return false;
                }
 
-               $ltPos = strpos( $str, '<' );
-               if ( $ltPos === false || $ltPos > $colonPos ) {
+               if ( $m[0][0] === ':' ) {
                        # Easy; no tag nesting to worry about
+                       $colonPos = $m[0][1];
                        $before = substr( $str, 0, $colonPos );
                        $after = substr( $str, $colonPos + 1 );
                        return $colonPos;
@@ -405,9 +405,10 @@ class BlockLevelPass {
 
                # Ugly state machine to walk through avoiding tags.
                $state = self::COLON_STATE_TEXT;
-               $level = 0;
+               $ltLevel = 0;
+               $lcLevel = 0;
                $len = strlen( $str );
-               for ( $i = 0; $i < $len; $i++ ) {
+               for ( $i = $m[0][1]; $i < $len; $i++ ) {
                        $c = $str[$i];
 
                        switch ( $state ) {
@@ -418,7 +419,7 @@ class BlockLevelPass {
                                        $state = self::COLON_STATE_TAGSTART;
                                        break;
                                case ":":
-                                       if ( $level === 0 ) {
+                                       if ( $ltLevel === 0 ) {
                                                # We found it!
                                                $before = substr( $str, 0, $i );
                                                $after = substr( $str, $i + 1 );
@@ -428,35 +429,44 @@ class BlockLevelPass {
                                        break;
                                default:
                                        # Skip ahead looking for something interesting
-                                       $colonPos = strpos( $str, ':', $i );
-                                       if ( $colonPos === false ) {
+                                       if ( !preg_match( '/:|<|-\{/', $str, $m, PREG_OFFSET_CAPTURE, $i ) ) {
                                                # Nothing else interesting
                                                return false;
                                        }
-                                       $ltPos = strpos( $str, '<', $i );
-                                       if ( $level === 0 ) {
-                                               if ( $ltPos === false || $colonPos < $ltPos ) {
-                                                       # We found it!
-                                                       $before = substr( $str, 0, $colonPos );
-                                                       $after = substr( $str, $colonPos + 1 );
-                                                       return $i;
-                                               }
+                                       if ( $m[0][0] === '-{' ) {
+                                               $state = self::COLON_STATE_LC;
+                                               $lcLevel++;
+                                               $i = $m[0][1] + 1;
+                                       } else {
+                                               # Skip ahead to next interesting character.
+                                               $i = $m[0][1] - 1;
                                        }
-                                       if ( $ltPos === false ) {
-                                               # Nothing else interesting to find; abort!
-                                               # We're nested, but there's no close tags left. Abort!
-                                               break 2;
+                                       break;
+                               }
+                               break;
+                       case self::COLON_STATE_LC:
+                               # In language converter markup -{ ... }-
+                               if ( !preg_match( '/-\{|\}-/', $str, $m, PREG_OFFSET_CAPTURE, $i ) ) {
+                                       # Nothing else interesting to find; abort!
+                                       # We're nested in language converter markup, but there
+                                       # are no close tags left.  Abort!
+                                       break 2;
+                               } elseif ( $m[0][0] === '-{' ) {
+                                       $i = $m[0][1] + 1;
+                                       $lcLevel++;
+                               } elseif ( $m[0][0] === '}-' ) {
+                                       $i = $m[0][1] + 1;
+                                       $lcLevel--;
+                                       if ( $lcLevel === 0 ) {
+                                               $state = self::COLON_STATE_TEXT;
                                        }
-                                       # Skip ahead to next tag start
-                                       $i = $ltPos;
-                                       $state = self::COLON_STATE_TAGSTART;
                                }
                                break;
                        case self::COLON_STATE_TAG:
                                # In a <tag>
                                switch ( $c ) {
                                case ">":
-                                       $level++;
+                                       $ltLevel++;
                                        $state = self::COLON_STATE_TEXT;
                                        break;
                                case "/":
@@ -486,10 +496,12 @@ class BlockLevelPass {
                        case self::COLON_STATE_CLOSETAG:
                                # In a </tag>
                                if ( $c === ">" ) {
-                                       $level--;
-                                       if ( $level < 0 ) {
+                                       if ( $ltLevel > 0 ) {
+                                               $ltLevel--;
+                                       } else {
+                                               # ignore the excess close tag, but keep looking for
+                                               # colons. (This matches Parsoid behavior.)
                                                wfDebug( __METHOD__ . ": Invalid input; too many close tags\n" );
-                                               return false;
                                        }
                                        $state = self::COLON_STATE_TEXT;
                                }
@@ -526,8 +538,11 @@ class BlockLevelPass {
                                throw new MWException( "State machine error in " . __METHOD__ );
                        }
                }
-               if ( $level > 0 ) {
-                       wfDebug( __METHOD__ . ": Invalid input; not enough close tags (level $level, state $state)\n" );
+               if ( $ltLevel > 0 || $lcLevel > 0 ) {
+                       wfDebug(
+                               __METHOD__ . ": Invalid input; not enough close tags " .
+                               "(level $ltLevel/$lcLevel, state $state)\n"
+                       );
                        return false;
                }
                return false;