CVS update: /cowiki/includes/cowiki/class/parse/

[email protected] 9 Apr 2005 23:34:08 -0000
Newsgroups gmane.comp.php.cowiki.cvs
Message-ID <[email protected]>
User: dgorski 
Date: 05/04/09 16:34:08

Modified:
 /cowiki/includes/cowiki/class/parse/
  class.WikiReverseParser.php, class.WikiParser.php

Log:
 Revert to the state that has worked for Boron release and plus a small fix after Boron, that is mentioned in the ChangeLog (bug #202).
 Until there is no other fully tested parser, there shouldn't be any half-hearted changes.

File Changes:

Directory: /cowiki/includes/cowiki/class/parse/
===============================================

File [changed]: class.WikiReverseParser.php
Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.WikiReverseParser.php?r1=1.16&r2=1.17
Delta lines:  +14 -63
---------------------
--- class.WikiReverseParser.php	21 Mar 2005 16:45:50 -0000	1.16
+++ class.WikiReverseParser.php	9 Apr 2005 23:34:07 -0000	1.17
@@ -2,7 +2,7 @@
 
 /**
  *
- * $Id: class.WikiReverseParser.php,v 1.16 2005/03/21 16:45:50 cmarble Exp $
+ * $Id: class.WikiReverseParser.php,v 1.17 2005/04/09 23:34:07 dgorski Exp $
  *
  * This file is part of coWiki. coWiki is free software under the terms of
  * the GNU General Public License (GPL). Read the LICENSE file. If you did
@@ -17,7 +17,7 @@
  * @author      Daniel T. Gorski, <[email protected]>
  * @copyright   (C) Daniel T. Gorski, {@link http://www.develnet.org}
  * @license     http://www.gnu.org/licenses/gpl.html
- * @version     $Revision: 1.16 $
+ * @version     $Revision: 1.17 $
  *
  */
 
@@ -135,6 +135,7 @@
         $sStr = $this->processPosting($sStr);
         $sStr = $this->processParagraph($sStr);
         $sStr = $this->processHeading($sStr);
+        $sStr = $this->processEmphasis($sStr);
         $sStr = $this->processHorizontalRule($sStr);
         $sStr = $this->processVariable($sStr);
         $sStr = $this->processPlugin($sStr);
@@ -143,10 +144,8 @@
         $sStr = $this->processBreak($sStr);
         $sStr = $this->processSup($sStr);
         $sStr = $this->processSub($sStr);
-	$sStr = $this->processJustification($sStr);
-        $sStr = $this->processEmphasis($sStr);
-        $sStr = $this->processTable($sStr);
         $sStr = $this->processList($sStr);
+        $sStr = $this->processTable($sStr);
         $sStr = $this->processQuote($sStr);    // last one!
 
         return trim(unescape($sStr));
@@ -434,38 +433,23 @@
      * @todo    [D11N]  Check description
      */
     protected function processEmphasis(&$sStr) {
-
-	//italic
         $sStr = preg_replace(
-            '=<(em|i)>(.*)</\1>=Ums',
-            '/\2/',
+            '=<em>(.*)</em>=Ums',
+            '/\1/',
             $sStr
         );
-	//bold
+
         $sStr = preg_replace(
-            '=<(strong|b)>(.*)</\1>=Ums',
-            '*\2*',
+            '=<strong>(.*)</strong>=Ums',
+            '*\1*',
             $sStr
         );
-	//monospaced
+
         $sStr = preg_replace(
             '=<tt>(.*)</tt>=Ums',
             '=\1=',
             $sStr
         );
-	//strikethrough
-        $sStr = preg_replace(
-            '=<strike>(.*)</strike>=Ums',
-            '--\1--',
-            $sStr
-        );
-	//underlined
-        $sStr = preg_replace(
-            '=<u>(.*)</u>=Ums',
-            '_\1_',
-            $sStr
-        );
-
         return $sStr;
     }
 
@@ -797,49 +781,27 @@
     protected function buildTable(&$aMatches) {
         $sStr = "\n&lt;table".$aMatches[1]."&gt;\n";
 
-	// Caption before first tr
-	if(preg_match(
-	    '=<caption>(.*)</caption>=Uis',
-	    $aMatches[2],
-	    $aCaption
-	)) {
-            $sStr .= "|+ " . $aCaption[1][0] . "\n";
-	}
-
         // Isolate rows
         preg_match_all(
-            '=<tr ?([^>]*)>(.+)</tr>=Uis',
+            '=<tr[^>]*>(.+)</tr>=USs',
             $aMatches[2],
             $aRows
         );
 
         // Treat cells
         for ($i=0, $n=sizeof($aRows[1]); $i<$n; $i++) {
-	    $sStr .= "|-" . trim($aRows[1][$i]) . "\n";
-
             preg_match_all(
-                '=<t(d|h) ?([^>]*)>(.*)</t\1>=Uis',
-                $aRows[2][$i],
+                '=<td colspan\="([0-9]+)">(.*)</td>=USs',
+                $aRows[1][$i],
                 $aCells
             );
 
             for ($j=0, $m=sizeof($aCells[1]); $j<$m; $j++) {
-	        switch($aCells[1][$j]){
-  		  case "d":
-		    $sSep = '|';
-		    break;
-		  case "h":
-		    $sSep = "!";
-		    break;
-		}
-	        if( strlen($aCells[2][$j]) ) {
-		    $sStr .= $sSep . trim($aCells[2][$j]) . "|\n" . $aCells[3][$j] ."\n";
-		} else {
-		    $sStr .= $sSep . "\n" . $aCells[3][$j] ."\n";
-		}
+                $sStr .= str_repeat('|', $aCells[1][$j]);
+                $sStr .= $aCells[2][$j];
             }
 
-            $sStr;
+            $sStr .= "\n";
         }
 
         return $sStr . "&lt;/table&gt;\n";
@@ -886,17 +848,6 @@
         $sStr = preg_replace(
             '=<sub>(.*)</sub>=Ums',
             "&lt;sub&gt;\\1&lt;/sub&gt;",
-            $sStr
-        );
-        return $sStr;
-    }
-
-    // --------------------------------------------------------------------
-
-    protected function processJustification(&$sStr) {
-        $sStr = preg_replace(
-            '=<(left|center|right)>(.*)</\\1>=Usi',
-            "&lt;\\1&gt;\\2&lt;/\\1&gt;",
             $sStr
         );
         return $sStr;

File [changed]: class.WikiParser.php
Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.WikiParser.php?r1=1.48&r2=1.49
Delta lines:  +139 -398
-----------------------
--- class.WikiParser.php	29 Mar 2005 13:40:52 -0000	1.48
+++ class.WikiParser.php	9 Apr 2005 23:34:07 -0000	1.49
@@ -2,7 +2,7 @@
 
 /**
  *
- * $Id: class.WikiParser.php,v 1.48 2005/03/29 13:40:52 cmarble Exp $
+ * $Id: class.WikiParser.php,v 1.49 2005/04/09 23:34:07 dgorski Exp $
  *
  * This file is part of coWiki. coWiki is free software under the terms of
  * the GNU General Public License (GPL). Read the LICENSE file. If you did
@@ -21,7 +21,7 @@
  * @author      Daniel T. Gorski, <[email protected]>
  * @copyright   (C) Daniel T. Gorski, {@link http://www.develnet.org}
  * @license     http://www.gnu.org/licenses/gpl.html
- * @version     $Revision: 1.48 $
+ * @version     $Revision: 1.49 $
  *
  */
 
@@ -31,115 +31,27 @@
 
     // On the other hand, the coWiki syntax is quite loose and is not easy
     // to express by a BNF parser, IMO.
-/**
- * coWiki token "no operation"
- */
-define('WIKI_TOKEN_NOOP',          1);
-
-/**
- * coWiki token "preformated"
- */
-define('WIKI_TOKEN_PRE',           2);
-
-/**
- * coWiki token "source code"
- */
-define('WIKI_TOKEN_CODE',          3);
-
-/**
- * coWiki token "posting"
- */
-define('WIKI_TOKEN_POSTING',       4);
-
-/**
- * coWiki token "hyperlink"
- */
-define('WIKI_TOKEN_LINK',          5);
-
-/**
- * coWiki token "Uniform Ressource Identifier (URI)"
- */
-define('WIKI_TOKEN_URI',           6);
-
-/**
- * coWiki token "Table of Contents (ToC)"
- */
-define('WIKI_TOKEN_TOC',           7);
-
-/**
- * coWiki token "plugin with parameter(s)"
- */
-define('WIKI_TOKEN_PARAM_PLUGIN',  8);
-
-/**
- * coWiki token "plugin without parameter(s)"
- */
-define('WIKI_TOKEN_SIMPLE_PLUGIN', 9);
 
-/**
- * coWiki token "heading"
- */
-define('WIKI_TOKEN_HEADING',       10);
-
-/**
- * coWiki token "horicontal ruler"
- */
-define('WIKI_TOKEN_HR',            11);
-
-/**
- * coWiki token "list"
- */
-define('WIKI_TOKEN_LIST',          12);
-
-/**
- * coWiki token "quotation"
- */
-define('WIKI_TOKEN_QUOTE',         13);
-
-/**
- * coWiki token "system variable"
- */
-define('WIKI_TOKEN_VAR',           14);
-
-/**
- * coWiki token "line break"
- */
-define('WIKI_TOKEN_BREAK',         15);
-
-/**
- * coWiki token "table with parameter(s)"
- */
-define('WIKI_TOKEN_PARAM_TABLE',   16);
-
-/**
- * coWiki token "table without parameter(s)"
- */
-define('WIKI_TOKEN_SIMPLE_TABLE',  17);
-
-/**
- * coWiki token "remark"
- */
-define('WIKI_TOKEN_REM',           18);
-
-/**
- * coWiki token "subscript"
- */    
-define('WIKI_TOKEN_SUB',           19);
-
-/**
- * coWiki token "superscript"
- */    
-define('WIKI_TOKEN_SUP',           20);
-
-/**
- * coWiki token "justification"
- */    
-define('WIKI_TOKEN_JUSTIFICATION', 21);
-
-/**
- * coWiki token "emphasis"
- */    
-define('WIKI_TOKEN_EMPHASIS',      22);
+    define('WIKI_TOKEN_NOOP',          1);
+    define('WIKI_TOKEN_PRE',           2);
+    define('WIKI_TOKEN_CODE',          3);
+    define('WIKI_TOKEN_POSTING',       4);
+    define('WIKI_TOKEN_LINK',          5);
+    define('WIKI_TOKEN_URI',           6);
+    define('WIKI_TOKEN_TOC',           7);
+    define('WIKI_TOKEN_PARAM_PLUGIN',  8);
+    define('WIKI_TOKEN_SIMPLE_PLUGIN', 9);
+    define('WIKI_TOKEN_HEADING',       10);
+    define('WIKI_TOKEN_HR',            11);
+    define('WIKI_TOKEN_LIST',          12);
+    define('WIKI_TOKEN_QUOTE',         13);
+    define('WIKI_TOKEN_VAR',           14);
+    define('WIKI_TOKEN_BREAK',         15);
+    define('WIKI_TOKEN_PARAM_TABLE',   16);
+    define('WIKI_TOKEN_SIMPLE_TABLE',  17);
+    define('WIKI_TOKEN_REM',           18);
+    define('WIKI_TOKEN_SUB',           19);
+    define('WIKI_TOKEN_SUP',           20);
 
 /**
  * coWiki - Wiki parser class
@@ -181,8 +93,7 @@
             WIKI_TOKEN_PARAM_TABLE,
             WIKI_TOKEN_SIMPLE_TABLE,
             WIKI_TOKEN_SUB,
-            WIKI_TOKEN_SUP,
-	    WIKI_TOKEN_JUSTIFICATION
+            WIKI_TOKEN_SUP
         );
 
     // Helper
@@ -409,7 +320,7 @@
                 break;
 
             case WIKI_TOKEN_LIST:
-                $sStr = $this->createList($sStr, $mMeta);
+                $sStr = $this->createList($sStr);
                 break;
 
             case WIKI_TOKEN_SIMPLE_TABLE:
@@ -443,14 +354,6 @@
             case WIKI_TOKEN_SUP:
                 $sStr = $this->createSupElement($sStr);
                 break;
-
-            case WIKI_TOKEN_JUSTIFICATION:
-                $sStr = $this->createJustificationElement($sStr, $mMeta);
-                break;
-
-	    case WIKI_TOKEN_EMPHASIS:
-		$sStr = $this->createEmphasisElement($sStr, $mMeta);
-		break;
         }
 
         return $sStr;
@@ -487,7 +390,7 @@
     // --------------------------------------------------------------------
 
     /**
-     * Create a <<pre>>-element
+     * Create a <pre>-element
      *
      * @access  protected
      *
@@ -501,7 +404,7 @@
     // --------------------------------------------------------------------
 
     /**
-     * Create a <<code>>-element
+     * Create a <code>-element
      *
      * @access  protected
      *
@@ -756,45 +659,6 @@
         return '<sup>'.$sStr.'</sup>';
     }
 
-    // --------------------------------------------------------------------
-
-    protected function createJustificationElement(&$sStr, &$mMeta) {
-	return '<'.$mMeta.'>'.$this->invokeParagraphs($sStr).'</'.$mMeta.'>';
-    }
-
-    protected function createEmphasisElement(&$sStr, &$mMeta) {
-
-	$sOpen = $sClose = '';
-	for ($i=0 ; $i < strlen($mMeta) ; $i++ ){
-	    switch(substr($mMeta,$i,1)){
-		case '_':
-		    $sOpen .= "<u>";
-		    $sClose = "</u>".$sClose;
-		    break;
-		case '-':
-		    if(!strcmp(substr($mMeta,$i+1,1),'-')){
-			$sOpen .= "<strike>";
-			$sClose = "</strike>".$sClose;
-			$i++;
-		    }
-		    break;
-		case '=':
-		    $sOpen .= "<tt>";
-		    $sClose = "</tt>".$sClose;
-		    break;
-		case '*':
-		    $sOpen .= "<b>";
-		    $sClose = "</b>".$sClose;
-		    break;
-		case '/':
-		    $sOpen .= "<i>";
-		    $sClose = "</i>".$sClose;
-		    break;
-            }
-	}
-	return $sOpen . $sStr . $sClose;
-    }
-
     // --- Element creator helpers ----------------------------------------
 
     /**
@@ -986,6 +850,10 @@
         // processing.
         $sStr = $this->processToc($sStr);
 
+        // After this step all emphasis markups (bold, italic, ...) are
+        // converted. These markups are not tokenized.
+        $sStr = $this->processEmphasis($sStr);
+
         // After this step all headings (+, ++, +++ -> H1, H2, H3 etc.) are
         // tokenized for further processing.
         $sStr = $this->processHeading($sStr);
@@ -1009,14 +877,6 @@
         // After this step lists are tokenized for further processing.
         $sStr = $this->processList($sStr);
 
-        // After this step all emphasis markups (bold, italic, ...) are
-        // tokenized for further processing.
-        $sStr = $this->processEmphasis($sStr);
-
-	// After this step all <left>,<right> & <centre> are tokenized
-	// for further processing.
-	$sStr = $this->processJustification($sStr);
-
         // After this step all parameterized <table></table> are tokenized
         // for further processing.
         $sStr = $this->processParamTable($sStr);
@@ -1486,79 +1346,59 @@
      */
     protected function processEmphasis(&$sStr) {
 
-      /*
-	this ought to work, halfway between Boron and proper fixing
-
-	/x/ - italics
-	*x* - bold
-	--x-- - strikethrough
-	_x_ - underlined
-	=x= - monospaced
-      */
-
-      $sEmph= '(-{2}|[_=\*/]+)';
-      $sCont= '([^\n_=*/]*)';
-      $sWord= '([^ \n/](\S?|.*(\S|\t)))';
-
-        $sStr = $this->collapseEmphasis( $sStr );
-
-        $sStr = preg_replace_callback(
-            '~  ((-{2}|[_=*/])+)
-		(([^\n_=*/])+)
-                ((-{2}|[_=*/])+)
-            ~mix',
-	    array(&$this,'tokenizeEmphasis'),
-            $sStr
-        );
-
-        return $sStr;
-    }
-
-    protected function collapseEmphasis(&$sStr) {
+        // These are the possible start delimiters for bold, italic
+        // and monospace emphasis markups
+        $sStart = '(\[\'';
+
+        // These are the possible end delimiters for bold, italic
+        // and monospace emphasis markups
+        $sEnd = '\s,.;:!?()\[\]_-';
 
-	//italic
+        // Italic first, because we do not want to match "</foo>/bar"
         $sStr = preg_replace(
-            '=&lt;(em|i)&gt;(.*)&lt;/\1&gt;=ms',
-            '/\2/',
+            '~  ([^<])?
+                (\s|=|\*|&lt;br&gt;|&quot;|['.$sStart.'])
+                (/)
+                ([^ \n/](\S?|.*(\S|\t)))
+                \3
+                (?=['.$sEnd.']|\*|&lt;br&gt;|&quot;|=)      # do not eat up
+                                                            # trailing chars
+            ~Umix',
+            '\1\2<em>\4</em>\7',
             $sStr
         );
-	//bold
-        $sStr = preg_replace(
-            '=&lt;(strong|b)&gt;(.*)&lt;/\1&gt;=ms',
-            '*\2*',
-            $sStr
-        );
-	//monospaced
-        $sStr = preg_replace(
-            '=&lt;tt&gt;(.*)&lt;/tt&gt;=ms',
-            '=\1=',
-            $sStr
-        );
-	//strikethrough
+
+        // Bold
         $sStr = preg_replace(
-            '=&lt;strike&gt;(.*)&lt;/strike&gt;=ms',
-            '--\1--',
+            '~  (\s|=|<em>|&lt;br&gt;|&quot;|['.$sStart.'])
+                (\*)
+                ([^ \n\*](\S?|.*(\S|\t)))
+                \2
+                (?=['.$sEnd.']|=|&lt;br&gt;|&quot;|</em>)   # do not eat up
+                                                            # trailing chars
+            ~Umix',
+            '\1<strong>\3</strong>\6',
             $sStr
         );
-	//underlined
+
+        // Mono
         $sStr = preg_replace(
-            '=&lt;u&gt;(.*)&lt;/u&gt;=ms',
-            '_\1_',
+            '~  (\s|<em>|<strong>|&quot;|&lt;br&gt;|['.$sStart.'])
+                (=)
+                ([^ \n=](\S?|.*(\S|\t)))
+                \2
+                (?=['.$sEnd.']|&lt;br&gt;|&quot;|</em>|</strong>)  # do not
+                                                                   # eat up
+                                                                   # trailing
+                                                                   # chars
+            ~Umix',
+            '\1<tt>\3</tt>\6',
             $sStr
         );
 
         return $sStr;
     }
 
-    protected function tokenizeEmphasis(&$aMatches) {
-	//proper emphatic nesting	
-        if ($aMatches[1]==strrev($aMatches[5])) {
-	    return $this->tokenize($aMatches[3],WIKI_TOKEN_EMPHASIS, $aMatches[1]);
-	} else {
-	    return $aMatches[0];
-	}
-    }
-
     // --------------------------------------------------------------------
 
     /**
@@ -1784,23 +1624,6 @@
 
     // --------------------------------------------------------------------
 
-    protected function processJustification(&$sStr) {
-        $sStr = preg_replace_callback(
-            '=&lt;(left|center|right)&gt;(.*)&lt;/\1&gt;=Usi',
-	    array(&$this, 'tokenizeJustification'),
-            $sStr );
-
-        return $sStr;
-    }
-
-    // --------------------------------------------------------------------
-
-    protected function tokenizeJustification(&$aMatches) {
-        return $this->tokenize($aMatches[2], WIKI_TOKEN_JUSTIFICATION, $aMatches[1]);
-    }
-
-    // --------------------------------------------------------------------
-
     /**
      * Ordered and unordered bullet lists (Asterisk *, Hash #)
      *
@@ -1813,8 +1636,7 @@
 
         // Treat lists
         $sStr = preg_replace_callback(
-	    /* '=\n(( {0,})(\*|#)+ (.*))$=Us',*/
-            '=\n((\*|#) (.*)\n)(?! {0,}(\*|#))=Us',
+            '=\n((\*|#) .*\n)(?! {0,}(\*|#))=Us',
 	    array(&$this, 'tokenizeList'),
             $sStr
         );
@@ -1833,11 +1655,7 @@
      * @since   coWiki 0.3.0
      */
     protected function tokenizeList(&$aMatches) {
-	return "\n".$this->tokenize(
-		    $aMatches[1],
-		    WIKI_TOKEN_LIST,
-		    $this->processEmphasis($aMatches[4])
-		)."\n";
+        return "\n".$this->tokenize($aMatches[1], WIKI_TOKEN_LIST)."\n";
     }
 
     // --------------------------------------------------------------------
@@ -1850,7 +1668,7 @@
      * @author  Daniel T. Gorski, <[email protected]>
      * @since   coWiki 0.3.0
      */
-    protected function createList(&$sStr, &$mMeta) {
+    protected function createList(&$sStr) {
 
         // Fix multiple bullets at the beginning of the line.
         // E.g. fix sick things like this to make it intuitive:
@@ -1883,10 +1701,7 @@
         $this->aList = array();
 
         for ($i=0; $i<sizeof($aList[1]); $i++) {
-	  //$this->aList[$i]['TEXT'] = $this->restoreTokens($mMeta);
-	  //$this->aList[$i]['TEXT']  = $aList[3][$i];
-	    $sEmp = $this->restoreTokens($this->processEmphasis($aList[3][$i]));
-	    $this->aList[$i]['TEXT'] = $sEmp;
+            $this->aList[$i]['TEXT']  = $aList[3][$i];
             $this->aList[$i]['DEPTH'] = strspn($aList[1][$i], ' ');
             $this->aList[$i]['TYPE']  = $aList[2][$i];
         }
@@ -2055,149 +1870,75 @@
 
         $aRows = explode("\n", $sStr);
         $aTable = array();
-	$nHeads = 0;
-	$sRet = '';
-	$sContent = '';
-	$sTable = '';
-	$sRow = '';
-	$bPriorRow = false;
 
-	//$i = -1;
-	//$n = sizeof($aRows);
 	for ($i=0, $n=sizeof($aRows); $i<$n; $i++) {
-	  //while( ++$i < $n ) {
 
-            if (!strlen(trim($aRows[$i]))) {
+            // Row MUST start with pipe
+            if (strlen(trim($aRows[$i])) == 0 || $aRows[$i]{0} != '|') {
                 return '<tr valign="top"><td colspan="1">'.$sStr.'</td></tr>';
             }
 
-	    //rows expected to hold table syntax (pipes), may instead
-	    //make room for ongoing content (tables, lists, etc)
-	    $sRow = $aRows[$i]."\n";
-
-	    //find table syntax within a (long?) row
-	    while( strlen($sRow) && preg_match(
-		    '=^([\|!][-+]?)( {0,1}[^\|!\n]*)?=',
-		    $sRow,
-		    $aMatches) ) {
-
-		//found exploded row begins with pipe syntax, poss params
-		$sRow = substr( $sRow, strlen($aMatches[0]) );
-
-		$nType = 0;
-		//tables made of cells, headers, rows, caption
-		if ($aMatches[1]=="|") {
-		    $sRet .= '<td';
-		    $nType = 1;
-		}else if ($aMatches[1]=="!") {
-		    $sRet .= '<th';
-		    $nType = 2;
-		}else if ($aMatches[1]=="|-") {
-		    if ($bPriorRow) {
-		        $sRet .= "</tr>\n<tr";
-		    } else {
-			$sRet .= '<tr';
-		    }
-		    $nType = 3;
-		    $bPriorRow = true;
-		}else if ($aMatches[1]=="|+") {
-		    $sRet .= '<caption>'.$aMatches[2]."</caption>\n";
-		    continue 1;
-		}
-
-		//content can be large, room for it here
-		$sContent = '';
-
-		if ($aMatches[2]{0}==' ') {
-		  //left a space to denote no params
-		    $sRet .= '>';
-		    $sContent .= substr($aMatches[2],1);
-		    //expect double pipe, bang or newline
-		} elseif (strlen($aMatches[2])) {
-		  //got params. look for pipe syntax that blocked last preg
-		    $sRet .= ' '.unescape($aMatches[2]).'>';
-		    if (preg_match('=^\|([^\|!\n]*)=',$sRow,$aMatches)) {
-		      //got rest of pipe syntax (...|text)
-			$sContent .= $aMatches[1];
-			$sRow = substr( $sRow, strlen($aMatches[0]) );
-		    }
-		} else {
-		    $sRet .= '>';
-		}
-
-		//look ahead now.
-		if ($sRow == "\n") {
-		  //look ahead to close our content
-		    while( ++$i<$n ){
-			$sRow = $aRows[$i];
-			//pipe syntax (will force $sContent) to continue
-			if ($sRow{0} == '|' || $sRow{0} == '!') {
-			    $sRet .= $sContent;
-			    switch($nType){
-			      case 1:
-			        $sRet .= "</td>\n";
-			        break;
-			      case 2:
-			        $sRet .= "</th>\n";
-			        break;
-			    }
-			    --$i;
-			    continue 3;
-			    /*			    
-			} else if (preg_match("=^&lt;nest=i", $sRow)) {
-			    $sTable = $sRow."\n";
-			    while( ++$i < $n ){
-                                $sRow = $aRows[$i];
-			        if(preg_match("=^&lt;/nest&gt;=i", $sRow)) {
-			            $sTable .= $sRow."\n";
-				    $sTable = preg_replace("=^&lt;nest=i","&lt;table",$sTable);
-				    $sTable = preg_replace("=&lt;/nest=i","&lt;/table",$sTable);
-				    $sTable = $this->processSimpleTable( $sTable );
-				    $sTable = $this->processParamTable( $sTable );
-			            $sContent .= $this->restoreTokens( $sTable );
-			            continue 2;
-                                } else {
-				    $sTable .= $sRow."\n";
-			        }
-			    }
-			    */
-			} else {
-			    //non-pipe (ever-increasing) content
-			    $sContent .= $sRow;
-			}
-		    }
-		    $i = $n;
-		    $sRet .= $sContent;
-		    switch($nType){
-		      case 1:
-		        $sRet .= "</td>\n";
-		        break;
-		      case 2:
-		        $sRet .= "</th>\n";
-		        break;
-		    }
-		    continue 2;
-		} elseif ( ( $sRow{0} == "|" || $sRow{0} == "!") && 
-			($sRow{1} == "|" || $sRow{1} == "!") ) {
-		    $sRow = substr($sRow, 1);
-		    $sRet .= $sContent;
-		    switch($nType){
-		      case 1:
-			$sRet .= "</td>\n";
-			break;
-		      case 2:
-			$sRet .= "</th>\n";
-			break;
-		    }
-		    continue 1;
-	        }
-	    }
-	}
-	if( $bPriorRow ) {
-	    return $sRet."</tr>";
-	} else {
-	    return $sRet;
+            $aRows[$i] = substr($aRows[$i], 1);
+
+            // Row MAY have one (or more) trailing pipes
+            if (substr($aRows[$i], -1) == '|') {
+                $aRows[$i] = substr($aRows[$i], 0, -1);
 	}
+
+            // Mark and remember all <noop>s in table row
+            $this->aTblRowNoop = array();
+            $aRows[$i] = preg_replace_callback(
+                            '#(<noop>.*</noop>)#U',
+                            array(&$this, 'extractTableRowNoops'),
+                            $aRows[$i]
+                         );
+
+            // Exchange column delemiter
+            $aRows[$i] = str_replace('|', "\x02", $aRows[$i]);
+
+            // Restore <noop>s in table row
+            for ($j=0, $m=sizeof($this->aTblRowNoop); $j<$m; $j++) {
+                $aRows[$i] = preg_replace(
+                                "#\x01#",
+                                $this->aTblRowNoop[$j],
+                                $aRows[$i],
+                                1
+                             );
+            }
+
+            // Divide columns
+            $aCols = explode("\x02", $aRows[$i]);
+
+            $nSpan = 0;
+            $sRow = '';
+
+            for ($j=0, $m=sizeof($aCols); $j<$m; $j++) {
+
+                if (strlen($aCols[$j]) == 0) {
+                    $nSpan++;
+                    if ($j < $m-1) {
+                        continue;
+                    }
+                }
+
+                if ($nSpan) {
+                    $sRow .= '<td colspan="'.($nSpan+1).'">';
+                    $sRow .=   $aCols[$j];
+                    $sRow .= '</td>';
+                    $nSpan = 0;
+                    continue;
+                }
+
+                $sRow .= '<td colspan="1">'.$aCols[$j].'</td>';
+            }
+
+            $aTable[] = '<tr valign="top">'
+                          .$sRow
+                        .'</tr>';
+        }
+
+        $sTable = join('', $aTable);
+        return $sTable;
     }
 
     // --------------------------------------------------------------------