Re: [cowiki-dev] coWiki definition, new parser

Archie Campbell <[email protected]>
Newsgroups gmane.comp.php.cowiki.devel
Message-ID <[email protected]>
It's not pretty and there are some bleeding edges in this working copy.

I've done it like this because I can't stand <1><1></1></1> giving 
<1><1></1> and hurling the rest back on yourself. There are two bits 
doing noop, which is why the thing is broken, probably. That was a 
mistake, actually. Please toy with it. Be merciless with the copy and 
gentle with me, that's probably the best idea.

It may become necessary to permute the WikiReverseParser into something 
resembling the modified WikiParser.

I'll get there once the latter is well behaved.

So. I'm off to Scotland for a week; enjoy breaking things.

Regards,

Archie

Archie Campbell wrote:

> Guys,
>
> The WikiParser is trotting along nicely. I'm currently working on 
> links, to be followed by the toc and then variables and anything 
> leftover from Paul's specification the other day.
>
> I'm going on holiday to Scotland for 5 days; from tomorrow evening 
> until next Sunday, I'll be exclusively real world. I propose to send a 
> patch from 0.3.4 with the new parser as a work-in-progress. If you 
> chaps could patch an old copy of Boron and have some fun breaking 
> things, I'll also include a TEST.IDIOM document with brief 
> descriptions of any limitations that the code needs, even temporarily.
>
> The question is... where do I put the patch? And, should I go from 
> 0.3.4 or CVS HEAD?
>
> I'm actually quite enjoying the coding, which is nice. It looks 
> nothing like the old version, and has made strides in definition, I think.
>
> Regards,
>
> cmarble
>
> P.S. Post-AprilFD, would anyone at Google fancy a coWiki? chortle
>
> Sy wrote:
>
>>On Apr 2, 2005 2:54 AM, Daniel T. Gorski <[email protected]> wrote:
>>
>>  
>>
>>>>>I would like to have more features listed that are beyond other wikis and
>>>>>make coWiki special, very special :)
>>>>>        
>>>>>
>>
>>It is necessary to create a good document which describes things more
>>technically before the release of the Beauty milestone.  We will need
>>to distinguish ourselves from other solutions.  This document will
>>help us understand the coWiki "Character" and make that milestone more
>>profound.
>>
>>This is now on my to do list.  =/
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: [email protected]
>>For additional commands, e-mail: [email protected]
>>
>>
>>
>>  
>>

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
class.WikiParser.php (text/html, 46.7 KB)
<?php

/**
 *
 * $Id: class.WikiParser.php,v 1.36 2005/02/14 22:23:53 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
 * not receive a copy of the license and are not able to obtain it through
 * the internet, please send a note to <[email protected]> so we can mail
 * you a copy immediately.
 *
 * <pre>
 * Helping hands: Matt Ho <[email protected]>
 * </pre>
 *
 * @package     parse
 * @subpackage  class
 * @access      public
 *
 * @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.36 $
 *
 */

/**
 * coWiki - Wiki parser class
 *
 * @package     parse
 * @subpackage  class
 * @access      public
 *
 * @author      Daniel T. Gorski, <[email protected]>
 * @since       coWiki 0.3.0
 */
class WikiParser extends Object {

    protected static
        $Instance = null;
    protected $aToc = array();

    protected $aEmph = array();

    // --------------------------------------------------------------------

    /**
     * Get instance
     *
     * @access  public
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    public function getInstance() {
        if (!self::$Instance) {
            self::$Instance = new WikiParser;
        }
        return self::$Instance;
    }

    // --------------------------------------------------------------------

    /**
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function __construct() {}

    // --- Helper methods -------------------------------------------------

    /**
     * Set doc toc
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function setDocToc($sStr) {
        $this->sDocToc = $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Get doc toc
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function getDocToc() {
        return $this->sDocToc;
    }

    // --------------------------------------------------------------------

    /**
     * Get token count
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function getTokenCount() {
        return sizeof($this->aToken);
    }

    // --------------------------------------------------------------------

    /**
     * Set restore flag
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function setRestoreFlag($bFlag) {
        $this->bRestoreFlag = $bFlag;
    }

    // --------------------------------------------------------------------

    /**
     * Get restore flag
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function getRestoreFlag() {
        return $this->bRestoreFlag;
    }

    // --------------------------------------------------------------------

    // --- Element creators -----------------------------------------------

    /**
     * Create a <noop>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createNoopElement(&$sStr) {
        return '<noop>'.$sStr.'</noop>';
    }

    // --------------------------------------------------------------------

    /**
     * Create a <rem>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createRemarkElement(&$sStr) {
        return '<rem>'.$sStr.'</rem>';
    }

    // --------------------------------------------------------------------

    /**
     * Create a <<pre>>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createPreElement(&$sStr) {
        return "<pre>\r".str_replace("\n", "\r", $sStr)."\r</pre>";
    }

    // --------------------------------------------------------------------

    /**
     * Create a <<code>>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createCodeElement(&$sStr) {
        return "<code>\r".str_replace("\n", "\r", $sStr)."\r</code>";
    }

    // --------------------------------------------------------------------

    /**
     * Create a <posting>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createPostingElement(&$sStr) {
        return "<posting>\r".str_replace("\n", "\r", $sStr)."\r</posting>";
    }

    // --------------------------------------------------------------------

    /**
     * Create a simple <plugin>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createSimplePluginElement(&$sStr) {
        return '<plugin name="'.$sStr.'"/>';
    }

    // --------------------------------------------------------------------

    /**
     * Create a parameterized <plugin>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createParamPluginElement(&$sStr, &$sAttr) {
        if (trim($sAttr) == '') {
            return $this->createSimplePluginElement($sStr);
        }
        return '<plugin name="'.$sStr.'" '.trim(unescape($sAttr)).'/>';
    }

    // --------------------------------------------------------------------

    /**
     * Create a <h>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createHeadingElement(&$sStr, &$sLevel) {
        return '<h'.$sLevel.'>'.$sStr.'</h'.$sLevel.'>';
    }

    // --------------------------------------------------------------------

    /**
     * Create a <link>-element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createLinkElement($sStr) {
        $aStr = explode(')(', $sStr);

        $sStr =  '<link strref="';
        $sStr .=   str_replace('|','¦',trim($this->restoreTokens($aStr[0])));
        $sStr .= '">';
        $sStr .=   trim($this->restoreTokens($aStr[0]));
        $sStr .= '</link>';

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Create uri element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createUriElement(&$sStr) {
        $sStr = '<uri strref="'.$sStr.'"/>';
        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Create toc element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createTocElement() {
        // Setting $i = 0 leads to undesired repetition of the first
        // "title" element in a bullet list

        // The default behaviour of <toc> is not to display the first
        // level
        $i = 1;
        $sStr = '';

        if (sizeof($this->aToc) > 0) {
            $sStr = $this->buildToc($i, $this->aToc[$i]['DEPTH']);
            if ($sStr != '') {
                $sStr = '<ul>' . $sStr . '</ul>';
            }
        }

        return '<toc>'.$this->restoreTokens($sStr).'</toc>';
    }

    // --------------------------------------------------------------------

    /**
     * Create rule element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createRuleElement() {
        return '<hr/>';
    }

    // --------------------------------------------------------------------

    /**
     * Create simple table element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createSimpleTableElement(&$sStr) {
        return '<table>'
                  .$this->buildTable($sStr)
              .'</table>';
    }

    // --------------------------------------------------------------------

    /**
     * Create param table element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createParamTableElement(&$sStr, &$sAttr) {
        if (trim($sAttr) == '') {
            return $this->createSimpleTableElement($sStr);
        }
        return '<table '.trim(unescape($sAttr)).'>'
                  .$this->buildTable($sStr)
              .'</table>';
    }

    // --------------------------------------------------------------------

    /**
     * Create quote element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createQuoteElement(&$sStr) {
        return '<q>'.$this->invokeParagraphs($sStr).'</q>';
    }

    // --------------------------------------------------------------------

    /**
     * Create var element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createVarElement(&$sStr, &$sName) {
        return '<var name="'.$sName.'"/>';
    }

    // --------------------------------------------------------------------

    /**
     * Create break element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createBreakElement() {
        return '<br/>';
    }

    // --------------------------------------------------------------------

    /**
     * Create sub element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.3
     */
    protected function createSubElement(&$sStr) {
        return '<sub>'.$sStr.'</sub>';
    }

    // --------------------------------------------------------------------

    /**
     * Create sup element
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.3
     */
    protected function createSupElement(&$sStr) {
        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 ----------------------------------------

    /**
     * Generate "toc" (Document Table of Contents)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function buildToc(&$i, &$nDepth) {
        $sStr = '';

        // Iterate though all toc-entries
        while (isset($this->aToc[$i]['DEPTH'])
               && $this->aToc[$i]['DEPTH'] == $nDepth) {

            $sStr .= '<li>';
            $sStr .=    '<link topicref="'.($i+1).'">'.$sAlias.'</link>';

            $i++;

            // Recurse (indent) if toc-entry is nested
            if (isset($this->aToc[$i]['DEPTH'])) {

                if ($this->aToc[$i]['DEPTH'] > $nDepth) {
                    $sStr .= '<ul>';
                    $sStr .=   $this->buildToc($i, $this->aToc[$i]['DEPTH']);
                    $sStr .= '</ul>';
                }
            }

            $sStr .= '</li>';
        }

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Catch paragraphs
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function invokeParagraphs(&$sStr) {
        // Remove multiple newlines
        $sStr = preg_replace('=\n+=', "\n", $sStr);

        // Insert paragraphs
        $sStr = preg_replace('=\n([^\r]+)$=Um', '<p>\1</p>', $sStr);

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * All strings passed to this method MUST NOT contain any "<" or ">".
     * Treat this string with "htmlentities()" or a similar function first.
     *
     * @access  public
     * @param   string  The wiki source string
     * @return  string  Wiki XML
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    public function parse($sStr) {

	$sRet = '';
	$sContent = '';
	$bList = false;
	$bTable = false;
	$bGreedy = false;
	$aList = array();
	$aTable = array();
	$aRows;

        // {{{ DEBUG }}}
        Logger::info('Start parsing wiki document.');

        // ---

        $sStr = trim(escape($sStr));

        // Replace possible tabulators
        $sStr = str_replace("\t", '    ', $sStr);

        // Replace possible \r\n or \n\r with \n
        $sStr = str_replace("\r\n", "\n", $sStr);
        $sStr = str_replace("\n\r", "\n", $sStr);

	$aRows = explode( "\n",$sStr."\n" );


        $i = 0; $n = sizeof( $aRows );
	$sRow = $aRows[$i]."\n";

	$t = 0; $l = -1;


	//table & list
	while( true ) {
	    $sContent = '';
	    $aMatches = array();
	    //table of contents alone ^<toc/>$
	    if( preg_match( '=^&lt;toc(/?)&gt;$=', $sRow ) ) {
		$sRet .= "\n\t\t\n";
	    //end of table
	    } else if( $t > 0 && preg_match( '=^&lt;/table&gt;=i',
						$sRow, $aMatches  )) {
	        $sParam = trim($aTable[$t][0]);
		if( $sParam == '') {
		    $sRet .= "\n".'<table>'.$this->buildTable($aTable[$t]).
		             '</table>'."\n";
		} else {
		    $sRet .= "\n".'<table '.trim(unescape($sParam)).'>'.
			         $this->buildTable($aTable[$t]).'</table>'."\n";
		}
		if( --$t == 0 ){
  		    $bTable = false;
		}
	    //beginning of table
	    } else if( preg_match( '=^&lt;table([^>]*)&gt;$=i',
					$sRow, $aMatches )) {
		$bTable = true;
		$aTable[++$t] = array();
		array_push( $aTable[$t], $aMatches[1] );
	    //beginning of list
	    } else if( preg_match( '=^([\s*#]{0,}[*#]) ([^\n]*)$=',
				    $sRow, $aMatches )) {
	        $bList = true;
		$aList[++$l] = array();
		$aList[$l]['TEXT'] = $this->processContent( $aMatches[2] );
		$aList[$l]['DEPTH'] = strlen( $aMatches[1] );
		$aList[$l]['TYPE'] = (substr($aMatches[1],-1)=='*'?
							      'ul':'ol');
	    //pre code posting q start at BOL, are greedy until 
	    // closing tag anywhere on a line
	    } else if (preg_match( '=^&lt;(pre|code|posting|q)&gt;=i',
				    $sRow, $aMatch ) ) {
	        $sRow = substr( $sRow, strlen($aMatch[0]) );
		do {
		    if (preg_match( '=(.*)&lt;/'.$aMatch[1].'&gt;=i',
				    $sRow, $aMatches )) {
			$sRet .= '<'.$aMatch[1].'>'.$sContent . 
				$aMatches[1].'</'.$aMatch[1].'>';
			break;
		    } else {
			$sContent .= $sRow;
		    }
		    if( ++$i < $n ){
		        $sRow = $aRows[$i];
		    }else{
		        break;
		    }
		} while(true);
		if( $i == $n ) {
		    $sRet .= '<'.$aMatch[1].'>'.
				$sContent .
				 '</'.$aMatch[1].'>';
		    break;
		}
	    //horizontal rule
	    } else if (preg_match( '=^-{3,}(\s|$)=', $sRow, $aMatches ) ) {
	        $sRet .= '<hr/>'."\n";
	    //noop
	    } else if (preg_match( '=((.*)&lt;noop&gt;)=i',
					$sRow, $aMatches )) {
		$sContent = $this->processContent( $aMatches[2], false )
				. '<noop>';
		$sRow = substr( $sRow, strlen($aMatches[1]) );
		do {
		    if (preg_match( '=(.*)&lt;/noop&gt;=' , 
				    $sRow, $aMatches )) {
  		        $sContent .= $aMatches[1] . '</noop>';
			break;
		    } else {
		        $sContent .= $sRow;
		    }
		    if(++$i<$n){
		        $sRow = $aRows[$i];
		    } else {
		        break;
		    }
		} while(true);
		$sRet .= $sContent;
	    } else {
		//end of list
		if($bList) {
		    $d = 0;
		    $sListType = $aList[$d]['TYPE'];
		    $nDepth = $aList[$d]['DEPTH'];
		    $sContent .= "\n".'<list>'.
				    '<'.$sListType.'>'.
				      $this->buildList($d,$nDepth,$aList).
				    '</'.$sListType.'>'.
		             '</list>'."\n";
    		    $bList = false;
		    $aList = array();
		    $l = -1;
		    if($bTable){
		        array_push( $aTable[$t], $sContent );
			array_push( $aTable[$t], $sRow );
		    }else{
			$sRet .= $sContent;
			$sRet .= $this->processContent( $sRow );
		    }
		//more table
		}else if($bTable) {
		    array_push( $aTable[$t], $sRow );
		//non table/list row
		}else{
		    $sContent = trim($this->processContent( $sRow ));
		    if( $sContent != '' ){
			$sRet .= '<p>'.$sContent.'</p>'."\n";
		    }
		}
	    }
	    if(sizeof($aMatches)) {
		$sRow = substr( $sRow, strlen( $aMatches[0] ) );
	    } else if ( ++$i < $n ) {
		$sRow = $aRows[$i]."\n";
	    } else {
	        break;
	    }
	}
	
	if( preg_match( '=^(.*)\n\t\t\n(.*)$=s', $sRet, $aMatches )) {
   	    $t = 1;
	    if (sizeof($this->aToc) > 0) {
		$sToc = $this->buildToc($t, $this->aToc[$t]['DEPTH']);
		if ($sToc != '') {
		    $sToc = '<ul>' . $sToc . '</ul>';
		}
	    }
	    return $aMatches[1] . $sToc . $aMatches[2];
	}

        // {{{ DEBUG }}}
        Logger::info('Finished parsing wiki document.');

	return $sRet;
    }

    protected function resetEmphasis() {
        $this->$aEmph = array(
		       "b" => false,
		       "u" => false,
		       "i" => false,
		       "f" => false,
		       "s" => false,
		       "j" => '',
		       "p" => ''
		);
    }

    protected function processContent( $sStr, $bClose = true ) {
        $sRet = '';
       	$aMatches = array();
	if ($bClose) {
	    $this->resetEmphasis();
	}
	$sStr = ltrim( $sStr );

	while( strlen( $sStr ) > 0 ) {
	    if ($sStr == "\n"){
		break;
	    }
	    //noop
	    if (preg_match( '=^&lt;noop&gt;(.*)&lt;/noop&gt;=is',
					$sStr, $aMatches )) {
	        $sRet .= '<noop>' . $aMatches[1] . '</noop>';
	    //links (()()) & [[][]]
	    }else if( preg_match( '=^\(\(([^\(\)]+|[^\(\)]+' .
				    '\([^\(\)]+\)[^\(\)]*|' .
			            '[^\(\)]+\)\([^\(\)]+)\)\)=Usx',
				  $sStr, $aMatches )) {
	        $aLink = explode( ')(', $aMatches[1] );
		$aLink[0] = str_replace( '|', '¦', $aLink[0] );
	        $sRet .= '<link strref="' . trim($aLink[0]) . '">';
		if ( isset( $aLink[1]) ) {
		    $sRet .= trim($aLink[1]);
		} else {
		    $sRet .= trim($aLink[0]);
		}
	        $sRet .= '</link>';
	    //WikiWords
	    }else if( preg_match( '=^([A-Z][a-z]+([A-Z][a-z]+)+)=s',
				    $sStr, $aMatches )) {
	      $sLink = trim(preg_replace( '=([A-Z])=', ' \1',
						$aMatches[1] ));
		$sRet .= '<link strref="' . $sLink . '">' .
				 $sLink . '</link>';
	    //URIs
	    }else if( preg_match(
		'=^(http://|https://|ftp://|mailto:|news:)
                   ([-_A-Z0-9\S]*)
                   (\*\s|\=\s|&quot;|&lt;|&gt;|<|>|\(|\)|\s|$)??
                 =six',
				  $sStr, $aMatches )) {
	        $sRet .= '<uri strref="' . 
				$aMatches[1].$aMatches[2] . '"/>';
	    //headings
	    }else if( preg_match( '=^(\+{1,})\s*(.*)$=s',
				    $sStr, $aMatches )) {
                $sContent = $this->processContent($aMatches[2]);
		if( preg_match( '=<link\s+strref\="([^>]+)">
						([^<]*)</link>=USx',
				$sContent, $aLinkMatches ) ) {
		    $sAlias = !empty($aLinkMatches[2])
                               ? $aLinkMatches[2]
                               : $aLinkMatches[1]
                               ;
		} else {
		    $sAlias = $sContent;
		}
		$i = sizeof($this->aToc);
		$this->aToc[$i]['TEXT'] = $sAlias;
		$this->aToc[$i]['DEPTH'] = strlen( $aMatches[1] );		
		$sTag = 'h'.strlen($aMatches[1]);
		$sRet .= '<'. $sTag .'>'.
			 $sContent .
			 '</'. $sTag .'>';
            //breaks
	    //justification
	    }else if( preg_match( '=^&lt;(/??)(left|center|right)&gt;=is',
				  $sStr, $aMatches )) {
	        if( $aMatches[1] == '/' &&
		    $this->aEmph['j'] == $aMatches[2]{0} ) {
		    $sRet .= '</'. $aMatches[2] .'>';
		    $this->aEmph['j'] = '';
		} else if ( $aMatches[1] == '' &&
			    $this->aEmph['j'] == '' ) {
		    $sRet .= '<'. $aMatches[2] .'>';
		    $this->aEmph['j'] = $aMatches[2]{0};
		}
	    //subscript, superscript
	    }else if( preg_match( '=^&lt;(/??)(sub|sup)&gt;=is',
				  $sStr, $aMatches ) ) {
	        if( $aMatches[1] == '/' &&
		    $this->aEmph['p'] == $aMatches[2] ) {
		    $sRet .= '</' . $aMatches[2] . '>';
		    $this->aEmph['p'] = '';
		}else if ( $aMatches[1] == '' &&
			   $this->aEmph['p'] == '' ) {
		    $sRet .= '<' . $aMatches[2] . '>';
		    $this->aEmph['p'] = $aMatches[2];
		}
	    //emphasis		
		
		/*
	    }else if( preg_match( '#^([^-=\*_/]*?)
 				      ([-=\*_/]{2,})
 	 			    ([^-=\*_/]*?)#x',
		*/		
				
	    }else if( preg_match( '#^([-=\*_/]{2,})#',
	 	      $sStr, $aMatches ) ) {
		while( strlen( $aMatches[1] ) ) {
		    if( strlen( $aMatches[1] ) >= 2 &&
			$aMatches[1]{0} == $aMatches[1]{1} ) {
			if( strlen( $aMatches[1] ) > 3 &&
			    $aMatches[1]{1} == $aMatches[1]{2} &&
			    $aMatches[1]{3} == $aMatches[1]{2} ) {
  			    $sRet .= str_repeat( $aMatches[1]{0}, 2 );
			    $aMatches[1] = substr( $aMatches[1], 4 );
			    continue;
			}
		        $sEmph = '';
		        switch ( $aMatches[1]{0} ) {
			case '-':
			    $sEmph=($this->aEmph["s"]?'/':'').'strike';
			    $this->aEmph["s"] = !$this->aEmph["s"];
			    break;
			case '=':
			    $sEmph=($this->aEmph["f"]?'/':'').'tt';
			    $this->aEmph["f"] = !$this->aEmph["f"];
			    break;
			case '*':
			    $sEmph=($this->aEmph["b"]?'/':'').'b';
			    $this->aEmph["b"] = !$this->aEmph["b"];
			    break;
			case '_':
			    $sEmph=($this->aEmph["u"]?'/':'').'u';
			    $this->aEmph["u"] = !$this->aEmph["u"];
			    break;
			case '/':
			    $sEmph=($this->aEmph["i"]?'/':'').'i';
			    $this->aEmph["i"] = !$this->aEmph["i"];
			    break;
			}
			$sRet .= '<'.$sEmph.'>';
		        $aMatches[1] = substr( $aMatches[1], 2 );
		    } else {
			$sRet .= $aMatches[1]{0};
			$aMatches[1] = substr( $aMatches[1], 1 );
		    }
		}
            }else if( preg_match( '#^((([-=\*_/]{1})(?!\3)|\s|[A-Za-z0-9])*)#x',
				    $sStr, $aMatches ) ) {
	        $sRet .= $aMatches[0];
	    }
	    if( isset($aMatches[0]) ) {
	        $sStr = substr( $sStr, strlen($aMatches[0]) );
	    }else{
	        break;
	    }
	}
	if($bClose) {
	    if( $this->aEmph['s'] ) { $sRet .= '</strike>'; }
	    if( $this->aEmph['f'] ) { $sRet .= '</tt>'; }
	    if( $this->aEmph['b'] ) { $sRet .= '</b>'; }
	    if( $this->aEmph['u'] ) { $sRet .= '</u>'; }
	    if( $this->aEmph['i'] ) { $sRet .= '</i>'; }
	    if( $this->aEmph['p'] != '' ) {
	        $sRet .= '</' . $this->aEmph['p'] .'>';
	    }   
	    $this->resetEmphasis();
	}
	/*
	if( $this->aEmph['j'] != '' ) {
	    switch( $this->aEmph['j'] ) {
	    case 'l': $sRet .= '</left>';break;
	    case 'r': $sRet .= '</right>';break;
	    case 'c': $sRet .= '</center>';break;
	    }
	}
	*/
	return $sRet;
    }

    /**
     * &build table
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function buildTable( &$aTable ) {

	$sRet = '';
	$sContent = '';
	$sRow = '';
	$bPriorRow = false;

	$j = 1;
	$v = sizeof($aTable);

	while( ++$j < $v ) {

	  /*
            if (!strlen(trim($aTable[$j]))) {
                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 = $aTable[$j];

	    //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>'.trim($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( ++$j<$v ){
			$sRow = $aTable[$j];
			//pipe syntax (will force $sContent) to continue
			if ($sRow{0} == '|' || $sRow{0} == '!') {
			    $sRet .= $this->processContent($sContent);
			    switch($nType){
			      case 1:
			        $sRet .= "</td>\n";
			        break;
			      case 2:
			        $sRet .= "</th>\n";
			        break;
			    }
			    --$j;
			    continue 3;
			} else {
			    //non-pipe (ever-increasing) content
			    $sContent .= $sRow;
			}
		    }
		    $j = $v;
		    $sRet .= $this->processContent($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 .= $this->processContent($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;
	}
    }

    protected function buildList(&$i, &$nDepth, &$aList) {
        $sStr = '';

        // Iterate though all list-entries
        while (isset($aList[$i]['DEPTH'])
               && $aList[$i]['DEPTH'] == $nDepth) {

            $sStr .= '<li>';
            $sStr .=    $aList[$i]['TEXT'];

            $i++;

            // Recurse (indent) if list-entry is nested
            if (isset($aList[$i]['DEPTH'])) {

                if ($aList[$i]['DEPTH'] > $nDepth) {

                    // Correct items that are intended too deep
                    $aList[$i]['DEPTH'] = $nDepth + 1;
                
                    $sListType = $aList[$i]['TYPE'];

                    $sStr .=  '<'.$sListType.'>';
                    $sStr .=    $this->buildList(
                                    $i,
                                    $aList[$i]['DEPTH'],
				    $aList
                                );
                    $sStr .=  '</'.$sListType.'>';
                }
            }

            $sStr .= '</li>';
        }

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat NOOP (no operation)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processNoOperation(&$sStr) {

        // Treat <noop> ... </noop>
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=&lt;noop&gt;(.+)&lt;/noop&gt;=Usi',
            array(&$this, 'tokenizeNoOperation'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat REMARKS
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processRemark(&$sStr) {

        // Treat <rem> ... </rem>
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=&lt;rem&gt;(.+)&lt;/rem&gt;=Usi',
            array(&$this, 'tokenizeRemark'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat preformatted PRE
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processPre(&$sStr) {

        // Treat <pre> ... </pre>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;pre&gt;\n(.+)\n&lt;/pre&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizePre'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat preformatted CODE
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processCode(&$sStr) {

        // Treat <code> ... </code>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;code&gt;\n(.+)\n&lt;/code&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizeCode'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat POSTING
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processPosting(&$sStr) {

        // Treat <posting> ... </posting>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;posting&gt;\n(.+)\n&lt;/posting&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizePosting'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * ((foo)), ((foo)(bar))
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processLink(&$sStr) {

        // Treat square-bracket-links ((foo)), ((foo)(bar))
        // These tags can not be nested.
        $sPattern = '=\(\(([^\(\)]+|[^\(\)]+\([^\(\)]+\)[^\(\)]*|' .
            '[^\(\)]+\)\([^\(\)]+)\)\)=U';

        $sStr = preg_replace_callback(
            $sPattern,
            array(&$this, 'tokenizeLink'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Convert WikiWords
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processWikiWord(&$sStr) {

        // Treat WikiWordLinks
        $sStr = preg_replace_callback(
            '=([ \n\[\{\']|&quot;)([A-Z][a-z]+([A-Z][a-z]+)+)=',
            array(&$this, 'tokenizeWikiWord'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Automatically clickable URIs
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processClickable(&$sStr) {

        // Treat clickable URIs (http:, mailto: etc.)
        $sStr = preg_replace_callback(
            '=  (http://|https://|ftp://|mailto:|news:)
                (\S+)
                (\*\s|\=\s|&quot;|&lt;|&gt;|<|>|\(|\)|\s|$)
             =Usmix',
            array(&$this, 'tokenizeClickable'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * <toc ...>
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processToc(&$sStr) {
        // Treat <toc ...>
        $sStr = preg_replace_callback(
            '=\n&lt;toc&gt;=Usi',
            array(&$this, 'tokenizeToc'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * <plugin ...>
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processSimplePlugin(&$sStr) {

        // Treat <plugin ...>
        $sStr = preg_replace_callback(
            '=&lt;plugin +([a-z0-9_.]+)&gt;=Usi',
            array(&$this, 'tokenizeSimplePlugin'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * <plugin ... parameters>
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processParamPlugin(&$sStr) {

        // Treat <plugin ... parameters>
        $sStr = preg_replace_callback(
            '=&lt;plugin +([a-z0-9_.]+) +(.*)&gt;=Usi',
            array(&$this, 'tokenizeParamPlugin'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Emphasis: bold, italic, monospaced ...
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processEmphasis(&$sStr) {

      /*
	emphasis markup may be as widely spaced as an entire paragraph

	/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) {

	//italic
        $sStr = preg_replace(
            '=&lt;(em|i)&gt;(.*)&lt;/\1&gt;=ms',
            '/\2/',
            $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
        $sStr = preg_replace(
            '=&lt;strike&gt;(.*)&lt;/strike&gt;=ms',
            '--\1--',
            $sStr
        );
	//underlined
        $sStr = preg_replace(
            '=&lt;u&gt;(.*)&lt;/u&gt;=ms',
            '_\1_',
            $sStr
        );

        return $sStr;
    }

    /**
     * (Again) treat %VARIABLES%, that may occur in the document.
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processVariable(&$sStr) {
        $sStr = preg_replace_callback(
                '=%([A-Z0-9_]+)%=U',
                array(&$this, 'tokenizeVariable'),
                $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Headings (+ -> H1, ++ -> H2, etc.)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processHeading(&$sStr) {

        // Treat headings (+, ++, +++ etc);
        // Each tag will be recognized at the begin of a line only!
        $sStr = preg_replace_callback(
            '=^(\+{1,6}) ([^\r\n]+)=m',
            array(&$this, 'tokenizeHeading'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Headings (+ -> H1, ++ -> H2, etc.)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processHorizontalRule(&$sStr) {

        // Treat horizontal rules (---)
        $sStr = preg_replace_callback(
            '=^-{3,}(\s|$)=m',
            array(&$this, 'tokenizeHorizontalRule'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Breaks (<br>)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processBreak(&$sStr) {

        // Treat a break
        $sStr = preg_replace_callback(
            '=&lt;br&gt;=Ui',
            array(&$this, 'tokenizeBreak'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Subs (<sub>)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.3
     */
    protected function processSub(&$sStr) {

        // Treat a <sub>
        $sStr = preg_replace_callback(
            '=&lt;sub&gt;(.*)&lt;/sub&gt;=Ui',
            array(&$this, 'tokenizeSub'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Sups (<sup>)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.3
     */
    protected function processSup(&$sStr) {

        // Treat a <sup>
        $sStr = preg_replace_callback(
            '=&lt;sup&gt;(.*)&lt;/sup&gt;=Ui',
            array(&$this, 'tokenizeSup'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    protected function processJustification(&$sStr) {
        $sStr = preg_replace_callback(
            '=&lt;(left|center|right)&gt;(.*)&lt;/\1&gt;=Usi',
	    array(&$this, 'tokenizeJustification'),
            $sStr );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Ordered and unordered bullet lists (Asterisk *, Hash #)
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processList(&$sStr) {

        // Treat lists
        $sStr = preg_replace_callback(
	    /* '=\n(( {0,})(\*|#)+ (.*))$=Us',*/
            '=\n((\*|#) (.*)\n)(?! {0,}(\*|#))=Us',
	    array(&$this, 'tokenizeList'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Create list
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function createList(&$sStr, &$mMeta) {

        // Fix multiple bullets at the beginning of the line.
        // E.g. fix sick things like this to make it intuitive:
        //
        // * Item 1     <-->   * Item 1
        //  * Item 2    <-->    * Item 2
        // ** Item 3    <-->    * Item 3
        // *** Item 4   <-->     * Item 4
        // **** Item 5  <-->      * Item 5
        // ** Item 6    <-->    * Item 6

        $aArr = explode("\n", $sStr);

        for ($i=0, $n=sizeof($aArr); $i<$n; $i++) {
            $aArr[$i] = preg_replace_callback(
                          '=^((\*|#)*)(\2) (.*)$=',
                          array($this, 'createListMultiBulletHelper'),
                          $aArr[$i]
                        );
        }

        $sStr = join("\n", $aArr);

        preg_match_all(
            '=^( {0,})(\*|#)+ (.*)$=Ums',
            $sStr,
            $aList
        );

        $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]['DEPTH'] = strspn($aList[1][$i], ' ');
            $this->aList[$i]['TYPE']  = $aList[2][$i];
        }

        $i = 0;
        $nDepth = $this->aList[$i]['DEPTH'];

        // Determine the type of the first list element:
        // Ordered or unordered?
        $sListType = ($aList[2][0] == '*') ? 'ul' : 'ol';

        return '<list>'
                  .'<'.$sListType.'>'
                      .$this->buildList($i, $nDepth)
                  .'</'.$sListType.'>'
              .'</list>';
    }

    private function createListMultiBulletHelper(&$aMatches) {
        return str_repeat(' ', strlen($aMatches[1]))
                .$aMatches[3].' '.$aMatches[4];
    }

    // --------------------------------------------------------------------

    /**
     * Build list
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    /**
     * Treat TABLE
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processSimpleTable(&$sStr) {

        // Treat <table> ... </table>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;table&gt;\n(.+)\n&lt;/table&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizeTable'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Process param table
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processParamTable(&$sStr) {

        // Treat <table> ... </table>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;table +([^>]*)&gt;\n(.+)\n&lt;/table&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizeParamTable'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Treat (block-)quote
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function processQuote(&$sStr) {

        // Treat <q> ... </q>
        // Each tag will be recognized at the begin of a line only!
        // This tag can not be nested.
        $sStr = preg_replace_callback(
            '=^&lt;q&gt;(.+)\n+&lt;/q&gt;(\s|$)=Umsi',
            array(&$this, 'tokenizeQuote'),
            $sStr
        );

        return $sStr;
    }

    // --------------------------------------------------------------------

    /**
     * Collect referenced nodes to where the document is linking to
     *
     * @access  protected
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    protected function addReferencedNode($Obj) {
        $this->RefNodes->add($Obj);
    }

    // --------------------------------------------------------------------

    /**
     * Get referenced nodes
     *
     * @access  public
     *
     * @author  Daniel T. Gorski, <[email protected]>
     * @since   coWiki 0.3.0
     */
    public function getReferencedNodes() {
        return $this->RefNodes;
    }

} // of class

/*
    Prospero:  That cross you wear around your neck; is it only a decoration,
               or are you a true Christian believer?

    Francesca: Yes, I believe - truly.

    Prospero:  Then I want you to remove it at once! - and never to wear it
               within this castle again! Do you know how a falcon is trained
               my dear? Her eyes are sown shut. Blinded temporarily she
               suffers the whims of her God patiently, until her will is
               submerged and she learns to serve - as your God taught and
               blinded you with crosses.

    Francesca: You had me take off my cross because it offended ...

    Prospero:  It offended no-one. No - it simply appears to me to be
               discourteous to ... to wear the symbol of a deity long dead.
               My ancestors tried to find it. And to open the door that
               seperates us from our Creator.

    Francesca: But you need no doors to find God. If you believe ...

    Prospero:  Believe?! If you believe you are gullible. Can you look
               around this world and believe in the goodness of a god who
               rules it? Famine, Pestilence, War, Disease and Death!
               They rule this world.

    Francesca: There is also love and life and hope.

    Prospero:  Very little hope I assure you. No. If a god of love and life
               ever did exist ... he is long since dead. Someone ...
               something rules in his place.
*/

?>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.