CVS update: /cowiki/includes/cowiki/class/parse/
[email protected] 29 May 2005 15:39:38 -0000
| Newsgroups | gmane.comp.php.cowiki.cvs |
|---|---|
| Message-ID | <[email protected]> |
User: cmarble Date: 2005/05/29 08:39:38 Added: cowiki/includes/cowiki/class/parse/class.TestWikiParser.php Modified: cowiki/includes/cowiki/class/parse/class.CoWikiParser.php cowiki/includes/cowiki/class/parse/class.CoWikiReverseParser.php cowiki/includes/cowiki/class/parse/class.WikiParser.php cowiki/includes/cowiki/class/parse/class.WikiReverseParser.php Log: Issue number: 152,174,195,198,208,196 Submitted by: cmarble New parser objects. Comprehensive test suite in misc/development/tests. File Changes: Directory: /cowiki/includes/cowiki/class/parse/ =============================================== File [changed]: class.CoWikiParser.php Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.CoWikiParser.php?r1=1.13&r2=1.14 Delta lines: +30 -27 --------------------- --- class.CoWikiParser.php 16 Jan 2005 23:25:09 -0000 1.13 +++ class.CoWikiParser.php 29 May 2005 15:39:35 -0000 1.14 @@ -2,7 +2,7 @@ /** * - * $Id: class.CoWikiParser.php,v 1.13 2005/01/16 23:25:09 dgorski Exp $ + * $Id: class.CoWikiParser.php,v 1.14 2005/05/29 15:39:35 cmarble 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.13 $ + * @version $Revision: 1.14 $ * */ @@ -30,6 +30,8 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * * @todo [D11N] Complete documentation */ @@ -53,18 +55,6 @@ return self::$Instance; } - /** - * Create link element - * - * @access protected - * @param string - * @return void - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ protected function __construct() {} // --- Element creators ----------------------------------------------- @@ -78,10 +68,12 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function createLinkElement($sStr) { + protected function createLinkElement($sStr, $bSquare = false) { - $aStr = explode(')(', $sStr); + $aStr = explode(($bSquare?"][":")("),$sStr); $sRef = false; $sAlias = false; @@ -98,7 +90,7 @@ $sPattern = '^(http://|https://|ftp://|mailto:|news:).*'; if (preg_match('=' . $sPattern . '=', $sRef)) { - return $this->createUriLinkElement($sRef, $sAlias); + return $this->createUriLinkElement($sRef, $sAlias, $bSquare); } // Obviously the reference string is not an URI. Check if it has @@ -109,12 +101,12 @@ if (sizeof($aWebRef) > 1) { $sWeb = trim($aWebRef[0]); $sRef = trim($aWebRef[1]); - return $this->createGlobalLinkElement($sWeb, $sRef, $sAlias); + return $this->createGlobalLinkElement($sWeb, $sRef, $sAlias, $bSquare); } // The reference string was not an URI and it has no reference // to an other web -> Look up in database. - return $this->createLocalLinkElement($sRef, $sAlias); + return $this->createLocalLinkElement($sRef, $sAlias, $bSquare); } /** @@ -127,9 +119,12 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function createUriLinkElement($sRef, $sAlias) { - $sStr = '<link href="'. $sRef . '">'; + protected function createUriLinkElement($sRef, $sAlias, $bSquare) { + $sStr = '<link origin='.($bSquare?'"square"':'"round"'). + ' href="'. $sRef . '">'; if ($sAlias && $sAlias != '') { $sStr .= $sAlias ; @@ -151,8 +146,10 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function createGlobalLinkElement($sWeb, $sRef, $sAlias) { + protected function createGlobalLinkElement($sWeb, $sRef, $sAlias, $bSquare) { $Context = RuntimeContext::getInstance(); $sWebStr = unescape($sWeb); @@ -188,14 +185,16 @@ $this->addReferencedNode($Node); // Create element - $sStr = '<link idref="' . $Node->get('id') . '">'; + $sStr = '<link origin='.($bSquare?'"square"':'"round"'). + ' idref="' . $Node->get('id') . '">'; $sStr .= $sAlias; $sStr .= '</link>'; } } if (!is_object($WebNode) || !is_object($Node)) { - $sStr = '<link strref="' . $sWeb . '¦' . $sRef . '">'; + $sStr = '<link origin='.($bSquare?'"square"':'"round"'). + ' strref="' . $sWeb . '¦' . $sRef . '">'; $sStr .= $sAlias; $sStr .= '</link>'; } @@ -213,8 +212,10 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function createLocalLinkElement($sRef, $sAlias) { + protected function createLocalLinkElement($sRef, $sAlias, $bSquare) { $Context = RuntimeContext::getInstance(); // Get current directory/document object @@ -236,13 +237,15 @@ $this->addReferencedNode($NewNode); // Create element - $sStr = '<link idref="' . $NewNode->get('id') . '">'; + $sStr = '<link origin='.($bSquare?'"square"':'"round"'). + ' idref="' . $NewNode->get('id') . '">'; $sStr .= $sAlias; $sStr .= '</link>'; } if (!is_object($NewNode)) { - $sStr = '<link strref="' . $sRef . '">'; + $sStr = '<link origin='.($bSquare?'"square"':'"round"'). + ' strref="' . $sRef . '">'; $sStr .= $sAlias; $sStr .= '</link>'; } File [changed]: class.CoWikiReverseParser.php Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.CoWikiReverseParser.php?r1=1.15&r2=1.16 Delta lines: +61 -12 --------------------- --- class.CoWikiReverseParser.php 16 Jan 2005 23:25:09 -0000 1.15 +++ class.CoWikiReverseParser.php 29 May 2005 15:39:35 -0000 1.16 @@ -2,7 +2,7 @@ /** * - * $Id: class.CoWikiReverseParser.php,v 1.15 2005/01/16 23:25:09 dgorski Exp $ + * $Id: class.CoWikiReverseParser.php,v 1.16 2005/05/29 15:39:35 cmarble 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.15 $ + * @version $Revision: 1.16 $ * */ @@ -30,6 +30,8 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * * @todo [D11N] Complete documentation */ @@ -124,6 +126,8 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * * @todo [D11N] Check description */ @@ -140,7 +144,15 @@ // If no referenced document was found if (!is_object($RefNode)) { - return '['.__('I18N_DOC_DELETED_DOCUMENT').']'; + if ($aMatches[0]=='square') { + return '['.'['.$aMatches[1].']['.$aMatches[2].']'. + __('I18N_DOC_DELETED_DOCUMENT').']'; + + } else { + return '['.'('.$aMatches[1].')('.$aMatches[2].')'. + __('I18N_DOC_DELETED_DOCUMENT').']'; + + } } // Normalize! @@ -165,26 +177,53 @@ // Link directly to a web with an alias if ($aMatches[2] != '') { + if( $aMatches[0]=='square' ) { + return '[['.$sPrefix.']['.escape($aMatches[2]).']]'; + } else { return '(('.$sPrefix.')('.escape($aMatches[2]).'))'; } + } // Link directly to a web without alias + if ($aMatches[0]=='square') { + return '[['.$sPrefix.']]'; + } else { return '(('.$sPrefix.'))'; } } + } // --- // Generate normal link without alias if ($aMatches[2] == '') { + if ($aMatches[0]=='square') { + return + '[[' + .$sPrefix + .escape($RefNode->get('name')) + .']]'; + } else { return '((' .$sPrefix .escape($RefNode->get('name')) .'))'; } + } // Generate normal link with an alias + if ($aMatches[0] == 'square' ) { + return '[' + .'[' + .$sPrefix + .$this->noopDelimiters(escape($RefNode->get('name'))) + .']' + .'[' + .escape($aMatches[2]) + . ']' + .']'; + } else { return '(' .'(' .$sPrefix @@ -194,7 +233,7 @@ .escape($aMatches[2]) . ')' .')'; - + } } /** @@ -206,14 +245,24 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * * @todo [D11N] Check description */ protected function buildHyperRefLink(&$aMatches) { if (trim($aMatches[2]) == '') { + if( $aMatches[0] == 'square' ) { + return '[[' . $aMatches[1] . ']]'; + } else { return '((' . $aMatches[1] . '))'; } + } + if( $aMatches[0] == 'square' ) { + return '[[' . $aMatches[1] . '][' . $aMatches[2] . ']]'; + } else { return '((' . $aMatches[1] . ')(' . $aMatches[2] . '))'; + } } } // of class File [added]: class.TestWikiParser.php Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.TestWikiParser.php?rev=1.1&content-type=text/vnd.viewcvs-markup Added lines: 0 -------------- File [changed]: class.WikiParser.php Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.WikiParser.php?r1=1.49&r2=1.50 Delta lines: +770 -1855 ------------------------ --- class.WikiParser.php 9 Apr 2005 23:34:07 -0000 1.49 +++ class.WikiParser.php 29 May 2005 15:39:35 -0000 1.50 @@ -2,7 +2,7 @@ /** * - * $Id: class.WikiParser.php,v 1.49 2005/04/09 23:34:07 dgorski Exp $ + * $Id: class.WikiParser.php,v 1.50 2005/05/29 15:39:35 cmarble 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,38 +21,10 @@ * @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.49 $ + * @version $Revision: 1.50 $ * */ - // We should solve this with lex/yacc (flex/bison), but mass hosters - // usually do not allow their users to execute binaries. So let's - // fight this (dumb) way. - - // On the other hand, the coWiki syntax is quite loose and is not easy - // to express by a BNF parser, IMO. - - 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 * @@ -62,1958 +34,901 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ class WikiParser extends Object { protected static $Instance = null; - - // Containers for the <toc> - table of contents (headings). - protected - $aToc = array(), - $sDocToc = false; - - // Container for tokenized strings - protected - $aToken = array(); - - // Elements that do NOT reside in <P>-paragraphs - protected - $aNonPara = array( - WIKI_TOKEN_PRE, - WIKI_TOKEN_CODE, - WIKI_TOKEN_POSTING, - WIKI_TOKEN_TOC, - WIKI_TOKEN_PARAM_PLUGIN, - WIKI_TOKEN_SIMPLE_PLUGIN, - WIKI_TOKEN_HEADING, - WIKI_TOKEN_HR, - WIKI_TOKEN_LIST, - WIKI_TOKEN_QUOTE, - WIKI_TOKEN_PARAM_TABLE, - WIKI_TOKEN_SIMPLE_TABLE, - WIKI_TOKEN_SUB, - WIKI_TOKEN_SUP - ); - - // Helper + protected $aToc = array(), + $aRows = array(), + $iRow = 0; protected - $RefNodes = null, $aList = array(), - $aTblRowNoop = array(); - + $aTable = array(), + $t = 0, + $l = 0, + $bList = false, + $bTable = false; + protected $RefNodes = null; // -------------------------------------------------------------------- /** - * Get instance + * Collect referenced nodes to where the document is linking to * - * @access public + * @access protected * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - public function getInstance() { - if (!self::$Instance) { - self::$Instance = new WikiParser; - } - return self::$Instance; + protected function addReferencedNode($Obj) { + $this->RefNodes->add($Obj); } // -------------------------------------------------------------------- /** - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function __construct() {} - - // --- Helper methods ------------------------------------------------- - - /** - * Set doc toc + * Get referenced nodes * - * @access protected + * @access public * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - protected function setDocToc($sStr) { - $this->sDocToc = $sStr; + public function getReferencedNodes() { + return $this->RefNodes; } - // -------------------------------------------------------------------- - /** - * Get doc toc + * Get instance * - * @access protected + * @access public * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - protected function getDocToc() { - return $this->sDocToc; + public function getInstance() { + if (!self::$Instance) { + self::$Instance = new WikiParser; + } + return self::$Instance; } // -------------------------------------------------------------------- /** - * Get token count - * * @access protected * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - protected function getTokenCount() { - return sizeof($this->aToken); + protected function __construct() { } - // -------------------------------------------------------------------- + // --- Helper methods ------------------------------------------------- /** - * Set restore flag - * * @access protected * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - protected function setRestoreFlag($bFlag) { - $this->bRestoreFlag = $bFlag; - } - - // -------------------------------------------------------------------- + protected function restoreTokens($sStr){ return $sStr; } /** - * Get restore flag + * Generate "toc" (Document Table of Contents) * * @access protected * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 */ - protected function getRestoreFlag() { - return $this->bRestoreFlag; - } + protected function buildToc(&$i, &$nDepth) { + $sStr = ''; - // -------------------------------------------------------------------- + // Iterate though all toc-entries + while (isset($this->aToc[$i]['DEPTH']) + && $this->aToc[$i]['DEPTH'] == $nDepth) { - /** - * Tokenize - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenize($sStr, $nType, $mMeta = false) { - $i = $this->getTokenCount(); + $sAlias = $this->aToc[$i]['TEXT']; + $sStr .= '<li>'; + $sStr .= '<link topicref="'.($i+1).'">'.$sAlias.'</link>'; + + $i++; + + // Recurse (indent) if toc-entry is nested + if (isset($this->aToc[$i]['DEPTH'])) { - $this->aToken[$i]['CONTENT'] = $sStr; - $this->aToken[$i]['TYPE'] = $nType; - $this->aToken[$i]['META'] = $mMeta; + if ($this->aToc[$i]['DEPTH'] > $nDepth) { + $sStr .= '<ul>'; + $sStr .= $this->buildToc($i, $this->aToc[$i]['DEPTH']); + $sStr .= '</ul>'; + } + } - // (Token-)Elements which do NOT reside in <P>-paragraphs, are - // marked with a leading \r as such. - if (in_array($nType, $this->aNonPara)) { - return "\r\t" . $i . "\t"; + $sStr .= '</li>'; } - return "\t" . $i . "\t"; + return $sStr; } // -------------------------------------------------------------------- + function finalizeList( &$sRow ) + { + $debug = false; + //end of list + if($this->bList) { + $d = 0; + $sListType = $this->aList[$d]['TYPE']; + $nDepth = $this->aList[$d]['DEPTH']; + $sContent = '<p><list>'. + '<'.$sListType.'>'. + $this->buildList($d,$nDepth,$this->aList). + '</'.$sListType.'>'. + '</list></p>'; + $this->bList = false; + $this->aList = array(); + $this->l = -1; + if($debug){ echo "finalizedList ".($this->bTable?"table":"ret")."\n"; } + if($this->bTable){ + array_push( $this->aTable[$this->t], $sContent ); + }else{ + return $sContent; + } + //more table + }else if($this->bTable) { + if ($debug) { echo "fin table row\n"; } + array_push( $this->aTable[$this->t], $sRow ); + $sRow = ''; + //non table/list row + }else{ + if ($debug) { echo "fin non table/list row\n"; } + $sContent = $this->processContent( $sRow ); + $sRow = ''; + if( $sContent != '' ){ + return '<p>'.$sContent.'</p>'; + } + } + } + /** - * Restore tokens + * parse * - * @access protected + * @access public + * @param string The wiki source string + * @return string Wiki XML * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function restoreTokens($sStr) { + public function parse($sStr) { - while (true) { - $this->setRestoreFlag(false); + $sRet = ''; + $sContent = ''; + $this->bList = false; + $this->bTable = false; + $bBegin = false; + $this->aList = array(); + $this->aTable = array(); + + $debug = false; + // {{{ DEBUG }}} + Logger::info('Start parsing wiki document.'); + + // Init reference collection + $this->RefNodes = new Vector; + + // --- + + $sStr = 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); + $sStr = str_replace("\r", "\n", $sStr); + + $this->aRows = explode( "\n",$sStr."\n" ); - $sStr = preg_replace_callback( - '=\r?\t([0-9]+)\t=US', - array(&$this, 'invokeTokens'), - $sStr - ); - if ($this->getRestoreFlag() == false) { + $this->iRow = 0; + $sRow = $this->aRows[$this->iRow]; + $bBegin = true; + + $this->t = 0; $this->l = -1; + + while( true ) { + $sContent = ''; + $aMatches = array(); + //table of contents alone ^<toc/>$ + if( $bBegin && preg_match( '=^<toc(/?)>$=', + $sRow, $aMatches )) { + $sRet .= "\n\t\t\n"; + //headings + }else if( $bBegin && preg_match( '=^(\+{1,})\s*(.*)$=s', + $sRow, $aMatches )) { + if ($debug) { echo "headings ".$aMatches[2]."\n"; } + $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 .'>'; + //end of table + } else if( $bBegin && ($this->t > 0) && + preg_match( '=^</table>=i', + $sRow, $aMatches )) { + if($debug) { echo "end of table ".$sRow."\n"; } + if($this->bTable && $this->bList) + { + $this->finalizeList( $sRow ); + } + $sParam = trim($this->aTable[$this->t][0]); + if( $sParam == '') { + $sRet .= '<table>'.$this->buildTable($this->aTable[$this->t]). + '</table>'; + } else { + $sRet .= '<table '.trim(unescape($sParam)).'>'. + $this->buildTable($this->aTable[$this->t]).'</table>'; + } + if( --$this->t == 0 ){ + $this->bTable = false; + } + //beginning of table + } else if( $bBegin && + preg_match( '=^<table([^>]*)>$=Ui', + $sRow, $aMatches )) { + if ($debug) { echo "begin table ".$aMatches[0]."\n"; } + $this->bTable = true; + $this->aTable[++$this->t] = array(); + array_push( $this->aTable[$this->t], $aMatches[1] ); + //beginning of list + } else if( $bBegin && + preg_match( '=^([\s*#]{0,}[*#]) ([^\n]*)$=', + $sRow, $aMatches )) { + if ($debug) { echo "begin list ".$aMatches[0]."\n"; } + $this->bList = true; + $this->aList[++$this->l] = array(); + $this->aList[$this->l]['TEXT'] = $this->processContent( $aMatches[2] ); + $this->aList[$this->l]['DEPTH'] = strlen( $aMatches[1] ); + $this->aList[$this->l]['TYPE'] = (substr($aMatches[1],-1)=='*'? + 'ul':'ol'); + //horizontal rule + } else if ($bBegin && + preg_match( '=^-{3,}(\s|$)=', + $sRow, $aMatches ) ) { + $sRet .= '<hr/>'."\n"; + } else { + if($debug) { echo "pre finalize sRow ".$sRow."\n"; } + $sRet .= $this->finalizeList( $sRow ); + if($debug) { echo "post finalize sRow ".$sRow."\n"; } + } + if(isset($aMatches[0])) { + $sRow = substr( $sRow, strlen( $aMatches[0] ) ); + $bBegin = false; + } + if ( trim($sRow) == '' ) { + if( ++$this->iRow < sizeof($this->aRows) ) { + if($debug) { echo "newline\n"; } + $sRow = $this->aRows[$this->iRow]; + $bBegin = true; + } else { break; } } + } - return $sStr; + if( preg_match( '=^(.*)\n\t\t\n(.*)$=s', $sRet, $aMatches )) { + $this->t = 0; + if (sizeof($this->aToc) > 0) { + $sToc = $this->buildToc($this->t, $this->aToc[$this->t]['DEPTH']); + if ($sToc != '') { + $sToc = '<toc><ul>' . $sToc . '</ul></toc>'; + } else { + $sToc = '<toc/>'; + } + } + return $aMatches[1] . $sToc . $aMatches[2]; } - // -------------------------------------------------------------------- + // {{{ DEBUG }}} + Logger::info('Finished parsing wiki document.'); + + return $sRet; + } /** - * Invoke tokens + * processContent * * @access protected + * @return string * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function invokeTokens(&$aMatches) { - $this->setRestoreFlag(true); - - $sStr = $this->aToken[$aMatches[1]]['CONTENT']; - $nType = $this->aToken[$aMatches[1]]['TYPE']; - $mMeta = $this->aToken[$aMatches[1]]['META']; - - $sStr = $this->restoreTokens($sStr); + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 + */ + protected function processContent( $sStr ) { + $sRet = ''; + $aMatches = array(); + + $sStr = ltrim( $sStr ); + $debug = false; + if($debug){echo "processContent ".$sStr."\n";} + while( $sStr != '' ) { + //paragraphs + if (preg_match( '=^<(/??)p>=i', $sStr, $aMatches) ) { + if($debug){echo "0\n";} + //pre code posting q rem and noop start are greedy until + // closing tag or eoln anywhere on a line + } else if (preg_match( '=^<(pre|code|posting|q|rem|noop)>=i', + $sStr, $aMatch ) ) { + if($debug){echo "1\n";} + $sStr = substr( $sStr, strlen($aMatch[0]) ); + $curLine = $this->iRow; + $curLen = strlen( $sStr ); + $sContent = ''; + while( !preg_match( '=^</'.$aMatch[1].'>=is', + $sStr, $aMatches ) ) { + if(preg_match( '#^<[^&]*>#is', $sStr, $aMatches )){ + $sContent .= $aMatches[0]; + $sStr = substr( $sStr, strlen( $aMatches[0] ) ); + } else if(preg_match( '=^([^&]|(\&(?!l)))*=is', $sStr, $aMatches )){ + $sContent .= $aMatches[0]; + $sStr = substr( $sStr, strlen( $aMatches[0] ) ); + } + if ( $sStr == '' ) { + if ( ++$this->iRow < sizeof($this->aRows) ) { + $sStr = $this->aRows[$this->iRow]; + $sContent .= "\n"; + } else { + $sStr = $this->aRows[$curLine]; + $sStr = substr( $sStr, strlen( $sStr )-$curLen ); + break; + } + } + } + if ( $this->iRow < sizeof($this->aRows) ) { + switch($aMatch[1]) + { + case 'rem': + case 'noop': + $sRet .= '<'.$aMatch[1].'>'.$sContent .'</'.$aMatch[1].'>'; + break; + default: + $aContent = explode( "\n",$sContent ); + $sContent = ''; + for( $i=0; $i < sizeof($aContent); $i++ ){ + $sContent .= $this->processContent($aContent[$i]); + } + $sRet .= '<'.$aMatch[1].'>'.$sContent.'</'.$aMatch[1].'>'; + break; + } + $sStr = substr( $sStr, strlen( $aMatches[0] ) ); + } else { + $this->iRow = $curLine; + $sRet .= '<'.$aMatch[1].'>'; + } + $aMatches = array(); + //line-break + }else if( preg_match( '=^<br(/?)>=is', $sStr, $aMatches )) { + if($debug){echo "2\n";} + $sRet .= '<br/>'; + //variables + }else if( preg_match( '=^%[A-Z0-9_]+$=is', $sStr, $aMatches ) ) { + if($debug){echo "3\n";} + $sRet .= $aMatches[0]; + }else if( preg_match( '=^%\s+=s', $sStr, $aMatches ) ) { + if($debug){echo "4\n";} + $sRet .= $aMatches[0]; + }else if( preg_match( '=^%([A-Z0-9_]+)%=Ui', $sStr, $aMatches )) { + if($debug){echo "5\n";} + $sRet .= '<var name="'.$aMatches[1].'"/>'; + //links (()()) + }else if( preg_match( '=^\(\('. + '([^\(\)]+\)\([^\(\)]+)'. + '\)\)=Usx', + $sStr, $aMatches )) { + if($debug){echo "6\n";} + $sRet .= $this->createLinkElement( $aMatches[1] ); + //links [[][]] + }else if( preg_match( '=^\[\['. + '([^\[\]]+\]\[[^\[\]]+)'. + '\]\]=Usx', + $sStr, $aMatches )) { + if($debug){echo "7\n";} + $sRet .= $this->createLinkElement( $aMatches[1], true ); + }else if( preg_match( '=^\(\([^\(\)]+\)?=Ui', $sStr, $aMatches )) { + if($debug){echo "8\n";} + $sRet .= $aMatches[0]; + }else if( preg_match( '=^\(?[^\(\)]+\)\)=Ui', $sStr, $aMatches )) { + if($debug){echo "9\n";} + $sRet .= $aMatches[0]; + }else if( preg_match( '=^[^\(\)]+\)\([^\(\)]+=Ui', $sStr, $aMatches )) { + if($debug){echo "10\n";} + $sRet .= $aMatches[0]; + /* + //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>'; + */ + /* + //urls + }else if( preg_match( '=^<url(\s+)( + (http://|https://|ftp://|mailto:|news:) + ([-_A-Z0-9\S]*) + (\*\s|\=\s|"|<|>|<|>|\(|\)|\s|$)?? + )>=six', + $sStr, $aMatches ) ) { + */ + //URIs + }else if( preg_match( + '=^(http://|https://|ftp://|mailto:|news:) + ([-\._A-Z0-9\S]*) + (\*\s|\=\s|"|<|>|<|>|\(|\)|\s|$)?? + =six', + $sStr, $aMatches )) { + if($debug){echo "12\n";} + $sRet .= '<uri strref="' . + $aMatches[1].$aMatches[2] . '"/>'; + /* + }else if( preg_match( '=^<plugin +([A-Za-z0-9_.]+)( +([^&]*))?(/?)>=i', + $sStr, $aMatches )) { + }else if( preg_match( '=^<plugin +([A-Za-z0-9_\.]+)(([^&]|&(?!g))*)(/?)>=i', + $sStr, $aMatches )) { + */ + //plugins + }else if( preg_match( '=^<plugin +([A-Za-z0-9_\.]+)( +([^&]|&(?!g))*)*(/?)>=i', + $sStr, $aMatches )) { + if($debug){echo "13 plugin ".$aMatches[0]."\n";} + if(isset($aMatches[2]) && $aMatches[2] != ''){ + $aMatches[2] = str_replace(""",'"',$aMatches[2]); + $sRet .= '<plugin name="'. + $aMatches[1].'"'.$aMatches[2].'/>'; + }else{ + $sRet .= '<plugin name="'.$aMatches[1].'"/>'; + } + //emphasis, subscript, superscript, justification + }else if( preg_match( '#^<(/??)(strike|tt|b|u|i|sub|sup|left|center|right)>#is', + $sStr, $aMatches ) ) { + if($debug){echo "14\n";} + switch($aMatches[2]{0}){ + case 'l': + case 'L': + if( $aMatches[1]=='/' ) { + $sRet .= "\x1E"; + } else { + $sRet .= "\x19"; + } + break; + case 'c': + case 'C': + if( $aMatches[1]=='/' ) { + $sRet .= "\x1F"; + } else { + $sRet .= "\x1A"; + } + break; + case 'r': + case 'R': + if( $aMatches[1]=='/' ) { + $sRet .= "\x7F"; + } else { + $sRet .= "\x1B"; + } + break; + case 's': + case 'S': + if(strtolower($aMatches[2])=="sub") { + if( $aMatches[1] =='/') { + $sRet .= "\x1C"; + } else { + $sRet .= "\x17"; + } + } else if(strtolower($aMatches[2])=="sup") { + if( $aMatches[1] =='/') { + $sRet .= "\x1D"; + } else { + $sRet .= "\x18"; + } + } else if(strtolower($aMatches[2])=="strike") { + if( $aMatches[1]=='/' ) { + $sRet .= "\x12"; + } else { + $sRet .= "\x06"; + } + } + break; + case 't': + case 'T': + if( $aMatches[1]=='/' ) { + $sRet .= "\x13"; + } else { + $sRet .= "\x0E"; + } + break; + case 'b': + case 'B': + if( $aMatches[1]=='/' ) { + $sRet .= "\x14"; + } else { + $sRet .= "\x0F"; + } + break; + case 'u': + case 'U': + if( $aMatches[1]=='/' ) { + $sRet .= "\x15"; + } else { + $sRet .= "\x10"; + } + break; + case 'i': + case 'I': + if( $aMatches[1]=='/' ) { + $sRet .= "\x16"; + } else { + $sRet .= "\x11"; + } + break; + } + //emphasis + }else if( preg_match( '#^([-=\*_/]{2})#', + $sStr, $aMatches ) ) { + if($debug){echo "15\n";} + if(preg_match( '#^['.$aMatches[1]{0}.']{1,}#', + substr($sStr,strlen($aMatches[0])), $aHead) ) { + $aMatches[0] .= $aHead[0]; + $sRet .= $aMatches[0]; + } else { + switch($aMatches[1]{0}){ + case '-': + $sRet .= "\x01"; + break; + case '=': + $sRet .= "\x02"; + break; + case '*': + $sRet .= "\x03"; + break; + case '_': + $sRet .= "\x04"; + break; + case '/': + $sRet .= "\x05"; + break; + } + } + //unknown tags + }else if( preg_match( '=^<[^>&]*=U', $sStr, $aMatches ) ) { + if($debug){echo "11 ".$aMatches[0]."\n";} + $sRet .= $aMatches[0]; + }else if( preg_match( '#^<[^>&]*>#', $sStr, $aMatches ) ) { + if($debug){echo "16 unknown ".$aMatches[0]."\n";} + $sRet .= $aMatches[0]; + /* + }else if( preg_match( '#^((([-=\*_/]{1})(?!\3))|[^-=\*_&%\(\[]|(&?!l))#Ui', + */ + }else if( preg_match( '#^((([-=\*_/]{1})(?!\3))|[^-=\*_&%\(\[]|&(?!l))#i', + $sStr, $aMatches ) ) { + if($debug){echo "17 ".$aMatches[0]."\n";} + $sRet .= $aMatches[0]; + } + if($debug){echo $sStr."\n";} + if( isset($aMatches[0]) ) { + $sStr = substr( $sStr, strlen($aMatches[0]) ); + } + } + //process emphasis tokens + $sStr = $sRet; + $sRet = ''; + $p = 0; + //while found wiki tokens (count) + //convert in pairs or replace (as we go) + $this->replaceWikiTokens("\x01","-","strike",$sStr); + $this->replaceWikiTokens("\x02","=","tt",$sStr); + $this->replaceWikiTokens("\x03","*","b",$sStr); + $this->replaceWikiTokens("\x04","_","u",$sStr); + $this->replaceWikiTokens("\x05","/","i",$sStr); + //while found html tokens (paired) + //correspond or replace (suitably as we go) + $this->replaceHtmlTokens("\x06","\x12","strike",$sStr); + $this->replaceHtmlTokens("\x0E","\x13","tt",$sStr); + $this->replaceHtmlTokens("\x0F","\x14","b",$sStr); + $this->replaceHtmlTokens("\x10","\x15","u",$sStr); + $this->replaceHtmlTokens("\x11","\x16","i",$sStr); + $this->replaceHtmlTokens("\x17","\x1C","sub",$sStr); + $this->replaceHtmlTokens("\x18","\x1D","sup",$sStr); + $this->replaceHtmlTokens("\x19","\x1E","left",$sStr); + $this->replaceHtmlTokens("\x1A","\x1F","center",$sStr); + $this->replaceHtmlTokens("\x1B","\x7F","right",$sStr); + + if($debug) { echo "processContent returns ".$sStr."\n"; } + return $sStr; + } + + protected function replaceWikiTokens( $char,$wiki,$sHtml, &$sStr ) { + $sRet = ''; + $open = false; + $c = substr_count($sStr,$char); + if(!$c) { return; } + while( $c ) { + if($sStr{0} == $char){ + if($c >= 2 || ($c == 1 && $open) ) { + $sRet .= '<'.($open?'/':'').$sHtml. + ($open?'':' origin="wiki"').'>'; + $open = !$open; + $c--; + } else { + $sRet .= str_repeat($wiki,2); + $c--; + } + } else { + $sRet .= $sStr{0}; + } + $sStr = substr($sStr,1); + } + $sRet .= $sStr; + $sStr = $sRet; + } + + protected function replaceHtmlTokens( $start, $end, $sHtml, &$sStr ) { + $sRet = ''; + $open = false; + $s = substr_count($sStr,$start); + $e = substr_count($sStr,$end); + if(!$s && !$e) { return; } + while( $s || $e ) { + if($sStr{0} == $start){ + if($e > 0){ + $sRet .= '<'.$sHtml.' origin="html">'; + $open = true; + } else { + $sRet .= '<'.$sHtml.'>'; + } + $s--; + } else if($sStr{0} == $end){ + if($open){ + $sRet .= '</'.$sHtml.'>'; + $open = false; + } else { + $sRet .= '</'.$sHtml.'>'; + } + $e--; + } else { + $sRet .= $sStr{0}; + } + $sStr = substr($sStr,1); + } + $sRet .= $sStr; + $sStr = $sRet; + } - switch ($nType) { - case WIKI_TOKEN_NOOP: - $sStr = $this->createNoopElement($sStr); - break; + /** + * &build table + * + * @access protected + * @return string + * + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 + */ + protected function buildTable( &$aTable ) { - case WIKI_TOKEN_REM: - $sStr = $this->createRemarkElement($sStr); - break; + $sRet = ''; + $sContent = ''; + $sRow = ''; + $bPriorRow = false; + $aMatches = array(); - case WIKI_TOKEN_PRE: - $sStr = $this->createPreElement($sStr); - break; + $debug = false; - case WIKI_TOKEN_CODE: - $sStr = $this->createCodeElement($sStr); - break; + $j = 0; + $v = sizeof($aTable); - case WIKI_TOKEN_POSTING: - $sStr = $this->createPostingElement($sStr); - break; + if($debug) { echo "aTable>".implode("\n",$this->aTable)."\n"; } - case WIKI_TOKEN_LINK: - $sStr = $this->createLinkElement($sStr); - break; + while( ++$j < $v ) { - case WIKI_TOKEN_URI: - $sStr = $this->createUriElement($sStr); - break; + /* + 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]; - case WIKI_TOKEN_TOC: - $sStr = $this->createTocElement(); - $this->setDocToc($sStr); - break; + if ($debug) { echo "while j ".$j." v ".$v." srow ".$sRow."\n"; } - case WIKI_TOKEN_PARAM_PLUGIN: - $sStr = $this->createParamPluginElement($sStr, $mMeta); - break; + //find table syntax within a (long?) row + while( strlen($sRow) && preg_match( + '=^([\|!]+[-+]?)( {0,1}[^\|!\n]*)?=', + $sRow, + $aMatches) ) { - case WIKI_TOKEN_SIMPLE_PLUGIN: - $sStr = $this->createSimplePluginElement($sStr); - break; + //found exploded row begins with pipe syntax, poss params + $sRow = substr( $sRow, strlen($aMatches[0]) ); - case WIKI_TOKEN_HEADING: - $sStr = $this->createHeadingElement($sStr, $mMeta); - break; + $nType = 0; + //tables made of cells, headers, rows, caption + 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; + }else if ($aMatches[1]{0}=="|") { + $sRet .= '<td'; + if ($aMatches[1] == "||") { + $nType = 4; + $sRet .= ' origin="doubled"'; + } else { + $nType = 1; + } + }else if ($aMatches[1]{0}=="!") { + $sRet .= '<th'; + $nType = 2; + } + //content can be large, room for it here + $sContent = ''; - case WIKI_TOKEN_LIST: - $sStr = $this->createList($sStr); - break; + //left a space to denote no params + if ($aMatches[2]{0} == ' ' || $aMatches[1] == "||") { + $sRet .= '>'; + $sContent .= substr($aMatches[2],1).$sRow; + //expect double pipe, bang or newline + } elseif (trim($aMatches[2])!='') { + //got params. look for pipe syntax that blocked last preg + $sRet .= ' '.unescape($aMatches[2]).'>'; - case WIKI_TOKEN_SIMPLE_TABLE: - $sStr = $this->createSimpleTableElement($sStr); - break; + //got rest of pipe syntax (...|text) + if (preg_match('=^\|(.*)$=',$sRow,$aMatches)) { + $sContent .= $aMatches[1]; + $sRow = substr( $sRow, strlen($aMatches[0]) ); + } + } else { + $sRet .= '>'; + } - case WIKI_TOKEN_PARAM_TABLE: - $sStr = $this->createParamTableElement($sStr, $mMeta); - break; + if($debug) { echo "sret ".$sRet." sRow ".$sRow." cont ".$sContent."\n"; } - case WIKI_TOKEN_HR: - $sStr = $this->createRuleElement(); + //look ahead now. + if (trim($sRow) == '' && $nType != 4) { + //look ahead to close our content + while( ++$j<$v ){ + if($debug) { echo " j ".$j." v ".$v."\n"; } + $sRow = $aTable[$j]; + //pipe syntax (will force $sContent) to continue + if ($sRow{0} == '|' || $sRow{0} == '!') { + if($debug) { echo "pipe ".$sRow."\n"; } + $sRet .= $this->processContent($sContent); + switch($nType){ + case 1: + $sRet .= "</td>\n"; break; - - case WIKI_TOKEN_QUOTE: - $sStr = $this->createQuoteElement($sStr); + case 2: + $sRet .= "</th>\n"; break; + } + --$j; + continue 3; + } else { + //non-pipe (ever-increasing) content + if($debug) { echo "nonpipe ".$sContent."\n"; } + $sContent .= $sRow; + } + } - case WIKI_TOKEN_VAR: - $sStr = $this->createVarElement($sStr, $mMeta); + $j = $v; + $sRet .= $this->processContent($sContent); + switch($nType){ + case 1: + $sRet .= "</td>\n"; break; - - case WIKI_TOKEN_BREAK: - $sStr = $this->createBreakElement(); + case 2: + $sRet .= "</th>\n"; break; - - case WIKI_TOKEN_SUB: - $sStr = $this->createSubElement($sStr); + } + continue 2; + } elseif ( ( $sRow{0} == "|" || $sRow{0} == "!") && + ($sRow{1} == "|" || $sRow{1} == "!") || + ( $nType == 4 ) ) { + $sRow = substr($sRow, 1); + $sRet .= $this->processContent($sContent); + switch($nType){ + case 1: + case 4: + $sRet .= "</td>\n"; break; - - case WIKI_TOKEN_SUP: - $sStr = $this->createSupElement($sStr); + case 2: + $sRet .= "</th>\n"; break; } - - return $sStr; + continue 1; + } + } + } + if( $bPriorRow ) { + if($debug) { echo $sRet."</tr>\n"; } + return $sRet."</tr>"; + } else { + if($debug) { echo $sRet."\n"; } + return $sRet; } - - // --- 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 + * &build list * * @access protected + * @return string * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 */ - protected function createRemarkElement(&$sStr) { - return '<rem>'.$sStr.'</rem>'; - } + protected function buildList(&$i, &$nDepth, &$aList) { + $sStr = ''; - // -------------------------------------------------------------------- + // Iterate though all list-entries + while (isset($aList[$i]['DEPTH']) + && $aList[$i]['DEPTH'] == $nDepth) { - /** - * 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>"; - } + $sStr .= '<li>'; + $sStr .= $aList[$i]['TEXT']; - // -------------------------------------------------------------------- + $i++; - /** - * 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>"; - } + // Recurse (indent) if list-entry is nested + if (isset($aList[$i]['DEPTH'])) { - // -------------------------------------------------------------------- + if ($aList[$i]['DEPTH'] > $nDepth) { - /** - * 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>"; - } + // Correct items that are indented too deep + $aList[$i]['DEPTH'] = $nDepth + 1; - // -------------------------------------------------------------------- + $sListType = $aList[$i]['TYPE']; - /** - * 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.'"/>'; + $sStr .= '<'.$sListType.'>'; + $sStr .= $this->buildList( + $i, + $aList[$i]['DEPTH'], + $aList + ); + $sStr .= '</'.$sListType.'>'; + } } - // -------------------------------------------------------------------- - - /** - * 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); + $sStr .= '</li>'; } - return '<plugin name="'.$sStr.'" '.trim(unescape($sAttr)).'/>'; + + return $sStr; } // -------------------------------------------------------------------- - - /** - * 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>'; - } - - // --- 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) { - - $sAlias = preg_replace( - '=<link[^>]*>=US', - '', - $this->aToc[$i]['TEXT'] - ); - - // replace link tokens - preg_match_all( - '=\r?\t([0-9]+)\t=US', - $sAlias, - $aMatchesAll, - PREG_SET_ORDER - ); - - foreach($aMatchesAll as $aMatches) { - if ($this->aToken[$aMatches[1]]['TYPE'] == WIKI_TOKEN_LINK) { - $sLinkElement = $this->createLinkElement( - $this->aToken[$aMatches[1]]['CONTENT'] - ); - - preg_match( - '=<link\s+href\="([^>]+)">([^<]*)</link>=US', - $sLinkElement, - $aLinkMatches - ); - - $sAlias = !empty($aLinkMatches[2]) - ? str_replace( - $aMatches[0], - $aLinkMatches[2], - $sAlias - ) - : str_replace( - $aMatches[0], - $aLinkMatches[1], - $sAlias - ); - } - } - - $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) { - - // {{{ DEBUG }}} - Logger::info('Start parsing wiki document.'); - - // --- - - $Registry = Registry::getInstance(); - - // Init reference collection - $this->RefNodes = new Vector; - - $sStr = trim(escape($sStr)); - - // WARNING: Be VERY VERY careful! The order of these processing - // steps is EXTREMELY important. Change only if you know what - // you are doing! AND then: test it, test it and test it again. - - // 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); - - // Let the string always start and end with a newline (\n). - // This makes pattern matching much easier. - $sStr = "\n" . $sStr . "\n"; - - // --- Tokenizing and preparing ----------------------------------- - - // After this step all <noop></noop> are tokenized for further - // processing. - $sStr = $this->processNoOperation($sStr); - - // After this step all <rem></rem> are tokenized for further - // processing. - $sStr = $this->processRemark($sStr); - - // After this step all <pre></pre> are tokenized for further - // processing. - $sStr = $this->processPre($sStr); - - // After this step all <code></code> are tokenized for further - // processing. - $sStr = $this->processCode($sStr); - - // After this step all <posting></posting> are tokenized for further - // processing. - $sStr = $this->processPosting($sStr); - - // After this step all parameterized <plugin ... param> are - // tokenized for further processing. - $sStr = $this->processParamPlugin($sStr); - - // After this step all simple <plugin ...> are tokenized for further - // processing. - $sStr = $this->processSimplePlugin($sStr); - - // After this step all bracket-links ((foo)), ((foo)(bar)) are - // tokenized for further processing. - $sStr = $this->processLink($sStr); - - // After this step all clickable URIs (http:// etc.) are tokenized - // for further processing. - $sStr = $this->processClickable($sStr); - - // After this step all WikiWords are tokenized for further processing. - if ($Registry->get('RUNTIME_WIKIWORDS')) { - $sStr = $this->processWikiWord($sStr); - } - - // After this step all variables are tokenized for further - // processing. - $sStr = $this->processVariable($sStr); - - // After this step all <toc ...> are tokenized for further - // 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); - - // After this step all horizontal rules (---) are tokenized for - // further processing. - $sStr = $this->processHorizontalRule($sStr); - - // After this step all breaks (<br>) are tokenized for further - // processing. - $sStr = $this->processBreak($sStr); - - // After this step all subs (<sub>) are tokenized for further - // processing. - $sStr = $this->processSub($sStr); - - // After this step all sups (<sup>) are tokenized for further - // processing. - $sStr = $this->processSup($sStr); - - // After this step lists are tokenized for further processing. - $sStr = $this->processList($sStr); - - // After this step all parameterized <table></table> are tokenized - // for further processing. - $sStr = $this->processParamTable($sStr); - - // After this step all simple <table></table> are tokenized for - // further processing. - $sStr = $this->processSimpleTable($sStr); - - // After this step all (block)-quotes are tokenized for further - // processing. - $sStr = $this->processQuote($sStr); - - // ---------------------------------------------------------------- - - // Insert paragraphs - $sStr = $this->invokeParagraphs($sStr); - - // Restore references (tokens) - $sStr = $this->restoreTokens($sStr); - - // <pre> or <code> escaped the paragraph invocation by replacing - // their newline delimiters to \r. - // Now we replace the delimiters back into \n again. - $sStr = str_replace("\r", "\n", $sStr); - - // {{{ DEBUG }}} - Logger::info('Finished parsing wiki document.'); - - 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( - '=<noop>(.+)</noop>=Usi', - array(&$this, 'tokenizeNoOperation'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize no operation - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeNoOperation(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_NOOP); - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=<rem>(.+)</rem>=Usi', - array(&$this, 'tokenizeRemark'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize remark - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeRemark(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_REM); - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<pre>\n(.+)\n</pre>(\s|$)=Umsi', - array(&$this, 'tokenizePre'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize pre - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizePre(&$aMatches) { - return $this->tokenize( - $aMatches[1], WIKI_TOKEN_PRE - ) - .$aMatches[2]; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<code>\n(.+)\n</code>(\s|$)=Umsi', - array(&$this, 'tokenizeCode'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize code - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeCode(&$aMatches) { - return $this->tokenize( - $aMatches[1], - WIKI_TOKEN_CODE - ) - .$aMatches[2]; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<posting>\n(.+)\n</posting>(\s|$)=Umsi', - array(&$this, 'tokenizePosting'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize posting - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizePosting(&$aMatches) { - return $this->tokenize( - $aMatches[1], WIKI_TOKEN_POSTING - ) - .$aMatches[2]; - } - - // -------------------------------------------------------------------- - - /** - * ((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; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize link - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeLink(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_LINK); - } - - // -------------------------------------------------------------------- - - /** - * 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\[\{\']|")([A-Z][a-z]+([A-Z][a-z]+)+)=', - array(&$this, 'tokenizeWikiWord'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize wiki word - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeWikiWord(&$aMatches) { - $sLink = preg_replace('=([A-Z])=', ' \1', $aMatches[2]); - return $aMatches[1].$this->tokenize(ltrim($sLink), WIKI_TOKEN_LINK); - } - - // -------------------------------------------------------------------- - - /** - * 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|"|<|>|<|>|\(|\)|\s|$) - =Usmix', - array(&$this, 'tokenizeClickable'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize clickable - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeClickable(&$aMatches) { - return $this->tokenize( - $aMatches[1] . $aMatches[2], WIKI_TOKEN_URI - ) - .$aMatches[3]; - } - - // -------------------------------------------------------------------- - - /** - * <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<toc>=Usi', - array(&$this, 'tokenizeToc'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize toc - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeToc(&$aMatches) { - return $this->tokenize(false, WIKI_TOKEN_TOC); - } - - // -------------------------------------------------------------------- - - /** - * <plugin ...> - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function processSimplePlugin(&$sStr) { - - // Treat <plugin ...> - $sStr = preg_replace_callback( - '=<plugin +([a-z0-9_.]+)>=Usi', - array(&$this, 'tokenizeSimplePlugin'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize simple plugin - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeSimplePlugin(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_SIMPLE_PLUGIN); - } - - // -------------------------------------------------------------------- - - /** - * <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( - '=<plugin +([a-z0-9_.]+) +(.*)>=Usi', - array(&$this, 'tokenizeParamPlugin'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize param plugin - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeParamPlugin(&$aMatches) { - return $this->tokenize( - $aMatches[1], WIKI_TOKEN_PARAM_PLUGIN, $aMatches[2] - ); - } - - // -------------------------------------------------------------------- - - /** - * Emphasis: bold, italic, monospaced ... - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function processEmphasis(&$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 first, because we do not want to match "</foo>/bar" - $sStr = preg_replace( - '~ ([^<])? - (\s|=|\*|<br>|"|['.$sStart.']) - (/) - ([^ \n/](\S?|.*(\S|\t))) - \3 - (?=['.$sEnd.']|\*|<br>|"|=) # do not eat up - # trailing chars - ~Umix', - '\1\2<em>\4</em>\7', - $sStr - ); - - // Bold - $sStr = preg_replace( - '~ (\s|=|<em>|<br>|"|['.$sStart.']) - (\*) - ([^ \n\*](\S?|.*(\S|\t))) - \2 - (?=['.$sEnd.']|=|<br>|"|</em>) # do not eat up - # trailing chars - ~Umix', - '\1<strong>\3</strong>\6', - $sStr - ); - - // Mono - $sStr = preg_replace( - '~ (\s|<em>|<strong>|"|<br>|['.$sStart.']) - (=) - ([^ \n=](\S?|.*(\S|\t))) - \2 - (?=['.$sEnd.']|<br>|"|</em>|</strong>) # do not - # eat up - # trailing - # chars - ~Umix', - '\1<tt>\3</tt>\6', - $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; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize variable - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeVariable(&$aMatches) { - return $this->tokenize(false, WIKI_TOKEN_VAR, $aMatches[1]); - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize heading - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeHeading(&$aMatches) { - - $nDepth = strlen($aMatches[1]); - - // Remember headings for <toc> - table of contents - $i = sizeof($this->aToc); - $this->aToc[$i]['TEXT'] = $aMatches[2]; - $this->aToc[$i]['DEPTH'] = $nDepth; - - return $this->tokenize($aMatches[2], WIKI_TOKEN_HEADING, $nDepth); - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize horizontal rule - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeHorizontalRule(&$aMatches) { - return $this->tokenize(false, WIKI_TOKEN_HR) . $aMatches[1]; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=<br>=Ui', - array(&$this, 'tokenizeBreak'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize break - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeBreak(&$aMatches) { - return $this->tokenize(false, WIKI_TOKEN_BREAK); - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=<sub>(.*)</sub>=Ui', - array(&$this, 'tokenizeSub'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize sub - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.3 - */ - protected function tokenizeSub(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_SUB); - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=<sup>(.*)</sup>=Ui', - array(&$this, 'tokenizeSup'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize sup - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.3 - */ - protected function tokenizeSup(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_SUP); - } - - // -------------------------------------------------------------------- - - /** - * 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((\*|#) .*\n)(?! {0,}(\*|#))=Us', - array(&$this, 'tokenizeList'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize list - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeList(&$aMatches) { - return "\n".$this->tokenize($aMatches[1], WIKI_TOKEN_LIST)."\n"; - } - - // -------------------------------------------------------------------- - - /** - * Create list - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function createList(&$sStr) { - - // 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'] = $aList[3][$i]; - $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 - */ - protected function buildList(&$i, &$nDepth) { - $sStr = ''; - - // Iterate though all list-entries - while (isset($this->aList[$i]['DEPTH']) - && $this->aList[$i]['DEPTH'] == $nDepth) { - - $sStr .= '<li>'; - $sStr .= $this->aList[$i]['TEXT']; - - $i++; - - // Recurse (indent) if list-entry is nested - if (isset($this->aList[$i]['DEPTH'])) { - - if ($this->aList[$i]['DEPTH'] > $nDepth) { - - // Correct items that are intended too deep - $this->aList[$i]['DEPTH'] = $nDepth + 1; - - $sListType = $this->aList[$i]['TYPE'] == '*' - ? 'ul' - : 'ol'; - - $sStr .= '<'.$sListType.'>'; - $sStr .= $this->buildList( - $i, - $this->aList[$i]['DEPTH'] - ); - $sStr .= '</'.$sListType.'>'; - } - } - - $sStr .= '</li>'; - } - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<table>\n(.+)\n</table>(\s|$)=Umsi', - array(&$this, 'tokenizeTable'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize table - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeTable(&$aMatches) { - return "\n" - .$this->tokenize($aMatches[1], WIKI_TOKEN_SIMPLE_TABLE) - ."\n"; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<table +([^>]*)>\n(.+)\n</table>(\s|$)=Umsi', - array(&$this, 'tokenizeParamTable'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize param table - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeParamTable(&$aMatches) { - return "\n" - .$this->tokenize( - $aMatches[2], WIKI_TOKEN_PARAM_TABLE, $aMatches[1] - ) - ."\n"; - } - - // -------------------------------------------------------------------- - - /** - * &build table - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function &buildTable(&$sStr) { - - $aRows = explode("\n", $sStr); - $aTable = array(); - - for ($i=0, $n=sizeof($aRows); $i<$n; $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>'; - } - - $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; - } - - // -------------------------------------------------------------------- - - private function extractTableRowNoops(&$aMatches) { - $this->aTblRowNoop[] = $aMatches[1]; - return "\x01"; - } - - // -------------------------------------------------------------------- - - /** - * 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( - '=^<q>(.+)\n+</q>(\s|$)=Umsi', - array(&$this, 'tokenizeQuote'), - $sStr - ); - - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Tokenize quote - * - * @access protected - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - */ - protected function tokenizeQuote(&$aMatches) { - return $this->tokenize($aMatches[1], WIKI_TOKEN_QUOTE) - .$aMatches[2]; - } - - // -------------------------------------------------------------------- - - /** - * 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 File [changed]: class.WikiReverseParser.php Url: http://cowiki.tigris.org/source/browse/cowiki/includes/cowiki/class/parse/class.WikiReverseParser.php?r1=1.17&r2=1.18 Delta lines: +612 -722 ----------------------- --- class.WikiReverseParser.php 9 Apr 2005 23:34:07 -0000 1.17 +++ class.WikiReverseParser.php 29 May 2005 15:39:35 -0000 1.18 @@ -2,7 +2,7 @@ /** * - * $Id: class.WikiReverseParser.php,v 1.17 2005/04/09 23:34:07 dgorski Exp $ + * $Id: class.WikiReverseParser.php,v 1.18 2005/05/29 15:39:35 cmarble 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.17 $ + * @version $Revision: 1.18 $ * */ @@ -30,12 +30,31 @@ * * @author Daniel T. Gorski, <[email protected]> * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * * @todo [D11N] Complete documentation */ class WikiReverseParser extends Object { protected static - $Instance = null; + $Instance = null, + $Context = null, + $DocDAO = null; + private + $rParser = null; + private + $ignoreToc = false, + $aList = array(), + $nDepth = 0, + $aType = array(), + $aTable = array(), + // $nTable = null; + $sLink = array(), + $fLink = array(), + $aState = array(0), + $sContent = '', + $aRow = array(), + $nListIndent = null; // -------------------------------------------------------------------- @@ -72,104 +91,11 @@ * * @todo [D11N] Check description */ - protected function __construct() {} - - // -------------------------------------------------------------------- - - /** - * Parse - * - * @access public - * @param string - * @return mixed - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - * @todo [D11N] Check return type - */ - public function parse($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); - - // Mark all newlines in <pre>, <code>, <posting> and <rem> as tabs - $sStr = preg_replace_callback( - '=(<pre>.*</pre>)=Usi', - array(&$this, 'newlineToTab'), - $sStr - ); - $sStr = preg_replace_callback( - '=(<code>.*</code>)=Usi', - array(&$this, 'newlineToTab'), - $sStr - ); - $sStr = preg_replace_callback( - '=(<posting>.*</posting>)=Usi', - array(&$this, 'newlineToTab'), - $sStr - ); - $sStr = preg_replace_callback( - '=(<rem>.*</rem>)=Usi', - array(&$this, 'newlineToTab'), - $sStr - ); - - // Remove all newlines - $sStr = str_replace("\n", '', $sStr); - // Restore newlines in <pre>s, <code>s and <posting>s - $sStr = str_replace("\t", "\n", $sStr); - - // --- - - $sStr = $this->processToc($sStr); - $sStr = $this->processNoop($sStr); - $sStr = $this->processRemark($sStr); - $sStr = $this->processPre($sStr); - $sStr = $this->processCode($sStr); - $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); - $sStr = $this->processLink($sStr); - $sStr = $this->processUri($sStr); - $sStr = $this->processBreak($sStr); - $sStr = $this->processSup($sStr); - $sStr = $this->processSub($sStr); - $sStr = $this->processList($sStr); - $sStr = $this->processTable($sStr); - $sStr = $this->processQuote($sStr); // last one! - - return trim(unescape($sStr)); + protected function __construct() { + $this->Context = RuntimeContext::getInstance(); + $this->DocDAO = $this->Context->getDocumentDAO(); } - // -------------------------------------------------------------------- - - /** - * Newline to tab - * - * @access protected - * @param array - * @return mixed - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - * @todo [D11N] Check return type - * @todo [FIX] THIS METHOD DO NOT COVER ALL POSSIBLE OCCURANCES OF DELIMITERS - */ - protected function newlineToTab(&$aMatches) { - return str_replace("\n", "\t", $aMatches[1]); - } // -------------------------------------------------------------------- @@ -214,672 +140,623 @@ // -------------------------------------------------------------------- /** - * Process toc - * - * @access protected - * @param string - * @return string + * Helper functions * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * - * @todo [D11N] Check description */ - protected function processToc(&$sStr) { - $sStr = preg_replace( - '=<toc>(.*)</toc>=Ums', - "\n<toc>\n", - $sStr - ); - return $sStr; + protected function appendRow($sStr){ + array_push($this->aRow,$sStr); + $this->clearContent(); } - - // -------------------------------------------------------------------- - - /** - * Process noop - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processNoop(&$sStr) { - $sStr = preg_replace( - '=<noop>(.*)</noop>=Ums', - "<noop>\\1</noop>", - $sStr - ); - return $sStr; + protected function clearContent(){ + $this->sContent = ''; } - - // -------------------------------------------------------------------- - - /** - * Process remark - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processRemark(&$sStr) { - $sStr = preg_replace( - '=<rem>(.*)</rem>=Ums', - "<rem>\\1</rem>", - $sStr - ); - return $sStr; + protected function clearRow() { + if(trim($this->sContent)!=''){ + $this->appendRow($this->sContent); } - - // -------------------------------------------------------------------- - - /** - * Process pre - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processPre(&$sStr) { - $sStr = preg_replace( - '=<pre>(.*)</pre>=Ums', - "\n<pre>\\1</pre>\n", - $sStr - ); - return $sStr; } - - // -------------------------------------------------------------------- - - /** - * Process code - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processCode(&$sStr) { - $sStr = preg_replace( - '=<code>(.*)</code>=Ums', - "\n<code>\\1</code>\n", - $sStr - ); - return $sStr; + protected function textListItem( $sData ) { + $this->aList[sizeof($this->aList)-1]['TEXT'] .= $sData; } - - // -------------------------------------------------------------------- - - /** - * Process posting - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processPosting(&$sStr) { - $sStr = preg_replace( - '=<posting>(.*)</posting>=Ums', - "\n<posting>\\1</posting>\n", - $sStr - ); - return $sStr; + protected function pushTableItem( $sData ) { + array_push($this->aTable[sizeof($this->aTable)-1],$sData); } - - // -------------------------------------------------------------------- - - /** - * Process paragraph - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processParagraph(&$sStr) { - $sStr = preg_replace( - '=<p>(.*)</p>=Ums', - "\n\\1\n", - $sStr - ); - return $sStr; + protected function textTableItem( $sData ) { + if(trim($this->sContent)!='') + { + $sStr = $this->sContent; + $this->clearContent(); + $this->textTableItem(trim($sStr)); } - - // -------------------------------------------------------------------- - - /** - * Process heading - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processHeading(&$sStr) { - $sStr = preg_replace_callback( - '=<h([1-6])>(.*)</h\1>=Ums', - array(&$this, 'buildHeading'), - $sStr - ); - return $sStr; + $a =& $this->aTable[sizeof($this->aTable)-1]; + $a[sizeof($a)-1] .= $sData; } - // -------------------------------------------------------------------- - /** - * Build heading + * Parse * - * @access protected - * @param array + * @access public + * @param string * @return mixed * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * - * @todo [D11N] Check description - * @todo [D11N] Check return type */ - protected function buildHeading(&$aMatches) { - return "\n" - .str_repeat('+', $aMatches[1]) - .' ' - .$aMatches[2] - ."\n"; - } + public function parse($sStr) { - // -------------------------------------------------------------------- + //return $this->dummy($sStr); - /** - * Process emphasis - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processEmphasis(&$sStr) { - $sStr = preg_replace( - '=<em>(.*)</em>=Ums', - '/\1/', - $sStr - ); - - $sStr = preg_replace( - '=<strong>(.*)</strong>=Ums', - '*\1*', - $sStr - ); - - $sStr = preg_replace( - '=<tt>(.*)</tt>=Ums', - '=\1=', - $sStr - ); - return $sStr; + if (!function_exists('xml_parser_create')) { + return false; } - // -------------------------------------------------------------------- + $this->rParser = @xml_parser_create(); - /** - * Process horizontal rule - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processHorizontalRule(&$sStr) { - $sStr = preg_replace( - '=<hr/>=Ums', - "\n---\n", - $sStr - ); - return $sStr; + if (!$this->rParser) { + return false; } - // -------------------------------------------------------------------- + xml_parser_set_option($this->rParser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->rParser, XML_OPTION_SKIP_WHITE, 1); - /** - * Process variable - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processVariable(&$sStr) { - $sStr = preg_replace( - '=<var name\="(.*)"/>=Ums', - '%\1%', - $sStr - ); - return $sStr; - } - - // -------------------------------------------------------------------- + // Replace possible tabulators + $sStr = str_replace("\t", ' ', $sStr); - /** - * Process link - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processLink(&$sStr) { - $sStr = preg_replace_callback( - '=<link strref\="(.*)">(.*)</link>=Ums', - array(&$this, 'buildStrRefLink'), - $sStr - ); - return $sStr; - } + // Replace possible \r\n or \n\r with \n + $sStr = str_replace("\r\n", "\n", $sStr); + $sStr = str_replace("\n\r", "\n", $sStr); - // -------------------------------------------------------------------- + // Prepare XML, add root element + $sStr = '<document>' . $sStr . '</document>'; - /** - * Build str ref link - * - * @access protected - * @param array - * @return mixed - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function buildStrRefLink(&$aMatches) { - if ($aMatches[1] == $aMatches[2] || trim($aMatches[2]) == '') { - return '((' . $this->noopDelimiters($aMatches[1]) . '))'; + xml_set_default_handler( $this->rParser, + array(&$this,'xml_default_handler') ); + xml_set_element_handler( $this->rParser, + array(&$this,'xml_start_handler'), + array(&$this,'xml_end_handler') ); + xml_set_character_data_handler( $this->rParser, + array(&$this,'xml_cdata_handler') ); + + if(!xml_parse( $this->rParser, $sStr )){ + echo xml_error_string(xml_get_error_code($this->rParser)); + } + + return implode("\n",$this->aRow); + + } + + /** + * xml element start handler + * + * @access protected + * + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 + * + */ + protected function xml_start_handler( &$parser, $sName, $aAttrib ) { + $debug = false; + if($debug) { + echo "start ".$sName." ".implode("|",$aAttrib)."\n"; + } + if($this->ignoreToc){ return; } + switch($sName){ + case 'document': + $this->aRow = array(); + break; + case 'toc': + $this->clearRow(); + $this->ignoreToc = true; + break; + case 'plugin': + $sStr = '<plugin '.$aAttrib['name']; + if(sizeof($aAttrib)>1){ + foreach($aAttrib as $attr => $value){ + if($attr != 'name'){ + $sStr .= ' '.$attr.'="'.$value.'"'; + } + } + } + $sStr .= '>'; + $this->sContent .= $sStr; + break; + //table syntax + case 'table': + $this->clearRow(); + array_push($this->aState,6);/*WRP_TABL*/ + array_push($this->aTable,array($aAttrib));//[][0] + break; + case 'caption': + array_push($this->aState,7);/*WRP_CAPN*/ + $this->clearContent(); + break; + case 'tr': + array_push($this->aState,8);/*WRP_TROW*/ + $sStr = '|-'; + if(sizeof($aAttrib)){ + $first = true; + foreach($aAttrib as $attr => $value){ + $sStr .= ($first?'':' ').$attr.'="'.$value.'"'; + $first = false; + } + } + $this->pushTableItem($sStr); + break; + case 'th': + array_push($this->aState,9);/*WRP_THED*/ + $sStr = '!'; + if(sizeof($aAttrib)){ + $first = true; + foreach($aAttrib as $attr => $value){ + $sStr .= ($first?'':' ').$attr.'="'.$value.'"'; + $first = false; } - - return '((' . $this->noopDelimiters($aMatches[1]) . ')' - .'(' . $aMatches[2] . '))'; + $sStr .= '|'; + } else { + $sStr .= ' '; } - - // -------------------------------------------------------------------- - - /** - * Process uri - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processUri(&$sStr) { - $sStr = preg_replace( - '=<uri strref\="(.*)"/>=Ums', - '\1', - $sStr - ); - return $sStr; + $this->pushTableItem($sStr); + break; + case 'td': + array_push($this->aState,10);/*WRP_TCEL*/ + $sStr = '|'; + if(sizeof($aAttrib)){ + $first = true; + foreach($aAttrib as $attr => $value){ + switch($attr) + { + case 'origin': + if( $value == 'doubled' ) { + $sStr .= '| '; + } + break; + default: + $sStr .= ($first?'':' ').$attr.'="'.$value.'"'; + $first = false; } - - // -------------------------------------------------------------------- - - /** - * Process break - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processBreak(&$sStr) { - $sStr = preg_replace( - '=<br/>=Ui', - "<br>", - $sStr - ); - return $sStr; } - - // -------------------------------------------------------------------- - - /** - * Process plugin - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processPlugin(&$sStr) { - $sStr = preg_replace_callback( - '=<plugin name\="([^"]+)"(.*)/>=Ums', - array(&$this, 'buildPlugin'), - $sStr - ); - return $sStr; + if($aAttrib['origin'] != 'doubled') { + $sStr .= '| '; } - - // -------------------------------------------------------------------- - - /** - * Build plugin - * - * @access protected - * @param array - * @return mixed - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function buildPlugin(&$aMatches) { - if ($aMatches[2] == '') { - return '<plugin '.$aMatches[1].'>'; } else { - return '<plugin '.$aMatches[1].' '.trim($aMatches[2]).'>'; - } + $sStr .= ' '; } - - // -------------------------------------------------------------------- - - /** - * Process list - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function processList(&$sStr) { - $sStr = preg_replace_callback( - '=<list>(.*)</list>=Ums', - array(&$this, 'buildList'), - $sStr - ); - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Build list - * - * @access protected - * @param array - * @return mixed - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - * @todo [D11N] Check return type - */ - protected function buildList(&$aMatches) { - // Remove closing </li> - $sStr = preg_replace('=</li>=i', '', $aMatches[1]); - $this->nListDepth = 0; - - $sList = ''; - return "\n" . $this->buildMixedList($sStr, $sList); + $this->pushTableItem($sStr); + break; + //list syntax + case 'list': + //$this->clearRow(); + array_push($this->aState,1);/*WRP_LIST*/ + break; + case 'ol': + case 'ul': + $this->nDepth++; + array_push($this->aType,$sName); + break; + case 'li': + switch(end($this->aState)){ + case 1: + array_push( $this->aList, + array( 'DEPTH'=>$this->nDepth, + 'TYPE'=>(end($this->aType)=='ol'? + "#":"*"), + 'TEXT'=>'' )); + break; + default: + echo $sName . "insanity"; + exit; + } + $this->clearContent(); + break; + //paragraphs + case 'p': + $this->clearRow(); + break; + //justification + case 'left': + case 'right': + case 'center': + array_push($this->aState,16); + $this->sContent .= '<'.$sName.'>'; + break; + //pre, code, posting, quote, remark, noop + case 'pre': + case 'code': + case 'posting': + case 'q': + case 'rem': + case 'noop': + $this->sContent .= '<'.$sName.'>'; + array_push($this->aState,4); + break; + //line-break + case 'br': + break; + //variables + case 'var': + $this->sContent .= "%".$aAttrib['name']."%"; + break; + //headings + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + array_push($this->aState,3); + break; + //wiki links + case 'uri': + $this->sContent .= $aAttrib['strref']; + break; + case 'link': + array_push($this->aState,2); + if( isset($aAttrib['strref']) ) { + $this->fLink = array(&$this, 'buildStrRefLink'); + $this->sLink[1] = $aAttrib['strref']; + }else if( isset($aAttrib['href']) ) { + $this->fLink = array(&$this, 'buildHyperRefLink'); + $this->sLink[1] = $aAttrib['href']; + }else if( isset($aAttrib['idref']) ) { + $this->fLink = array(&$this, 'buildIdRefLink'); + $this->sLink[1] = $aAttrib['idref']; + } + $this->sLink[0] = $aAttrib['origin']; + $this->sLink[2] = ''; + break; + //subscript & superscript + case 'sub': + case 'sup': + $this->sContent .= '<'.$sName.'>'; + break; + //horizontal rule + case 'hr':break; + //emphasis (strike,tt,b,u,i) + //WRP_ST WRP_TT WRP_B WRP_U WRP_I + //11 12 13 14 15 <- html + //17 18 19 20 21 <- wiki + case 'strike': + if(isset($aAttrib['origin']) && $aAttrib['origin']=='html'){ + array_push($this->aState,11); + $this->sContent .= "<strike>"; + }else{ + array_push($this->aState,17); + $this->sContent .= "--"; + } + break; + case 'tt': + if(isset($aAttrib['origin']) && $aAttrib['origin']=='html'){ + array_push($this->aState,12); + $this->sContent .= "<tt>"; + }else{ + array_push($this->aState,18); + $this->sContent .= "=="; + } + break; + case 'b': + if(isset($aAttrib['origin']) && $aAttrib['origin']=='html'){ + array_push($this->aState,13); + $this->sContent .= "<b>"; + }else{ + array_push($this->aState,19); + $this->sContent .= "**"; + } + break; + case 'u': + if(isset($aAttrib['origin']) && $aAttrib['origin']=='html'){ + array_push($this->aState,14); + $this->sContent .= "<u>"; + }else{ + array_push($this->aState,20); + $this->sContent .= "__"; + } + break; + case 'i': + if(isset($aAttrib['origin']) && $aAttrib['origin']=='html'){ + array_push($this->aState,15); + $this->sContent .= "<i>"; + }else{ + array_push($this->aState,21); + $this->sContent .= "//"; + } + break; + default: + echo $sName . " start" . "\n"; + } + } + + /** + * xml element end handler + * + * @access protected + * + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 + * + */ + protected function xml_end_handler( &$parser, $sName ) { + $debug = false; + if($debug) { + echo "end ".$sName."\n"; + } + if($this->ignoreToc){ + if($sName == 'toc'){ + $this->appendRow("<toc>"); + $this->ignoreToc = false; + return; + } + } + switch($sName){ + case 'document': + $this->clearRow(); + break; + case 'plugin': + break; + //table syntax + case 'table': + $this->clearContent(); + if(array_pop($this->aState)!=6) { + echo "insanity in table"; + exit; + } + $aTable = array_pop($this->aTable); + $sStr = '<table'; + foreach($aTable[0] as $attr => $value ){ + $sStr .= " ".$attr.'="'.$value.'"'; + } + $sStr .= (sizeof($aTable)==1?'/>':'>'); + if($debug) { echo $sStr." ".(sizeof($aTable)-1)."\n"; } + if($debug) { echo $sStr." ".implode(",",$aTable)."\n"; } + $this->appendRow( $sStr ); + for ($i = 1; $i < sizeof($aTable) ; $i++){ + if(trim($aTable[$i]) != '') { + if($debug) { echo $aTable[$i]."\n"; } + $this->appendRow( trim($aTable[$i]) ); + } + } + $this->appendRow('</table>'); + break; + //caption + case 'caption': + if(array_pop($this->aState)!=7) { + echo "insanity in caption"; + exit; + } + $this->pushTableItem( "|+ ".$this->sContent ); + $this->clearContent(); + break; + case 'tr': + if(array_pop($this->aState)!=8) { + echo "insanity in trow"; + exit; + } + $this->textTableItem(''); + break; + case 'th': + if(array_pop($this->aState)!=9) { + echo "insanity in thead"; + exit; + } + $this->textTableItem(''); + break; + case 'td': + if(array_pop($this->aState)!=10) { + echo "insanity in tcell"; + exit; + } + $this->textTableItem(''); + break; + //list syntax + case 'list': + if(array_pop($this->aState)!=1) { + echo "insanity in list"; + exit; + }; + foreach($this->aList as $li){ + $sStr = str_repeat($li['TYPE'],$li['DEPTH']). + " ".$li['TEXT']; + switch(end($this->aState)){ + case 9: + case 10: + $this->pushTableItem( $sStr ); + break; + default: + $this->appendRow( $sStr ); + } + } + $this->clearContent(); + $this->aList = array(); + break; + case 'ol': + case 'ul': + $this->nDepth--; + array_pop($this->aType); + break; + case 'li': + $this->clearContent(); + break; + //paragraphs + case 'p': + $this->appendRow( $this->sContent ); + break; + //justification + case 'left': + case 'right': + case 'center': + if(array_pop($this->aState)!=16){ + echo "insanity in just"; + exit; + } + $this->sContent .= '</'.$sName.'>'; + break; + //pre, code, posting, quote, remark, noop + case 'pre': + case 'code': + case 'posting': + case 'q': + case 'rem': + case 'noop': + $this->sContent .= '</'.$sName.'>'; + if(array_pop($this->aState)!=4){ + echo "insanity in pcpq"; + exit; + } + /* + if(end($this->aState)!=1){ + $this->clearRow(); + } + */ + break; + //line-break + case 'br': + $this->sContent .= '<br/>'; + break; + //variables + case 'var': + break; + //headings + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $this->appendRow( str_repeat("+",substr($sName,1,1)). + " ". $this->sContent); + array_pop( $this->aState ); + break; + //wiki links + case 'uri': + break; + case 'link': + if(array_pop($this->aState)!=2){ + echo "insanity in link"; + exit; + } + $sStr = call_user_func($this->fLink, $this->sLink); + $this->sContent .= $sStr; + break; + //subscript & superscript + case 'sub': + case 'sup': + $this->sContent .= '</'.$sName.'>'; + break; + //horizontal rule + case 'hr': + $this->appendRow("---"); + break; + //emphasis (strike,tt,b,u,i) + case 'strike': + if(array_pop($this->aState)==11){ + $this->sContent .= "</strike>"; + } else { + $this->sContent .= "--"; } - - // -------------------------------------------------------------------- - - /** - * Build mixed list - * - * @access protected - * @param string - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description - */ - protected function buildMixedList(&$sStr, &$sList) { - static $aListType = array(); - - $bMatch = preg_match('=<([^>]*)>([^<]*)(.*)=sS', $sStr, $aMatches); - - if ($bMatch) { - - if ($aMatches[1] == 'ul') { - $sListTag = '*'; - $aListType[$this->nListDepth] = '*'; - $this->nListDepth++; - $this->buildMixedList($aMatches[3], $sList); + break; + case 'tt': + if(array_pop($this->aState)==12){ + $this->sContent .= "</tt>"; + } else { + $this->sContent .= "=="; } - - if ($aMatches[1] == 'ol') { - $aListType[$this->nListDepth] = '#'; - $this->nListDepth++; - $this->buildMixedList($aMatches[3], $sList); + break; + case 'b': + if(array_pop($this->aState)==13){ + $this->sContent .= "</b>"; + } else { + $this->sContent .= "**"; } - - if ($aMatches[1] == 'li') { - $sList .= str_repeat(' ', $this->nListDepth - 1) - . $aListType[$this->nListDepth - 1] . ' ' - . str_replace("\n", '', $aMatches[2]) . "\n"; - $this->buildMixedList($aMatches[3], $sList); + break; + case 'u': + if(array_pop($this->aState)==14){ + $this->sContent .= "</u>"; + } else { + $this->sContent .= "__"; } - - if ($aMatches[1] == '/ul') { - $this->nListDepth--; - $this->buildMixedList($aMatches[3], $sList); + break; + case 'i': + if(array_pop($this->aState)==15){ + $this->sContent .= "</i>"; + } else { + $this->sContent .= "//"; } - - if ($aMatches[1] == '/ol') { - $this->nListDepth--; - $this->buildMixedList($aMatches[3], $sList); + break; + default: + echo $sName . " end" . "\n"; } + if(end($this->aState)==1){ + $this->textListItem($this->sContent); + $this->clearContent(); } - - return $sList; } - // -------------------------------------------------------------------- - /** - * Process table + * xml element default handler * * @access protected - * @param string - * @return string * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * - * @todo [D11N] Check description */ - protected function processTable(&$sStr) { - $sStr = preg_replace_callback( - '=<table([^>]*)>(.*)</table>=Ums', - array(&$this, 'buildTable'), - $sStr - ); - - return $sStr; + protected function xml_default_handler( &$parser, $sData ) { + if(!$this->ignoreToc){ + $this->sContent .= html_entity_decode($sData); + } } - - // -------------------------------------------------------------------- /** - * Build table + * xml cdata handler * * @access protected - * @param array - * @return mixed * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 + * @author Archie Campbell <[email protected]> + * @since coWiki 0.4.0 * - * @todo [D11N] Check description - * @todo [D11N] Check return type */ - protected function buildTable(&$aMatches) { - $sStr = "\n<table".$aMatches[1].">\n"; - - // Isolate rows - preg_match_all( - '=<tr[^>]*>(.+)</tr>=USs', - $aMatches[2], - $aRows - ); - - // Treat cells - for ($i=0, $n=sizeof($aRows[1]); $i<$n; $i++) { - preg_match_all( - '=<td colspan\="([0-9]+)">(.*)</td>=USs', - $aRows[1][$i], - $aCells - ); - - for ($j=0, $m=sizeof($aCells[1]); $j<$m; $j++) { - $sStr .= str_repeat('|', $aCells[1][$j]); - $sStr .= $aCells[2][$j]; + protected function xml_cdata_handler( &$parser, $sData ) { + $debug = false; + if( $debug ) { + echo "cdata ".$sData."\n"; } - - $sStr .= "\n"; + if($this->ignoreToc){ return; } + if( $sData != '' ) { + switch( end($this->aState) ){ + case 2:/*WRP_LINK*/ + $this->sLink[2] .= trim($sData); + break; + case 4:/*WRP_PCPQ*/ + $this->sContent .= /*trim*/($sData); + break; + case 1:/*WRP_LIST*/ + $this->textListItem($sData); + break; + case 9:/*WRP_THED*/ + case 10:/*WRP_TCEL*/ + $this->textTableItem($sData); + break; + case 3:/*WRP_HEAD*/ + case 7:/*WRP_CAPT*/ + default:/*text*/ + $this->sContent .= $sData; } - - return $sStr . "</table>\n"; } - - // -------------------------------------------------------------------- - - /** - * Process sup - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.4 - * - * @todo [D11N] Check description - */ - protected function processSup(&$sStr) { - $sStr = preg_replace( - '=<sup>(.*)</sup>=Ums', - "<sup>\\1</sup>", - $sStr - ); - return $sStr; } - - // -------------------------------------------------------------------- - - /** - * Process sub - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.4 - * - * @todo [D11N] Check description - */ - protected function processSub(&$sStr) { - $sStr = preg_replace( - '=<sub>(.*)</sub>=Ums', - "<sub>\\1</sub>", - $sStr - ); - return $sStr; - } - - // -------------------------------------------------------------------- - - /** - * Process quote - * - * @access protected - * @param string - * @return string - * - * @author Daniel T. Gorski, <[email protected]> - * @since coWiki 0.3.0 - * - * @todo [D11N] Check description + /* + case 11: emphases + case 12: + case 13: + case 14: + case 15: */ - protected function processQuote(&$sStr) { - $sStr = preg_replace_callback( - '=<q>(.*)</q>=Ums', - array(&$this, 'buildQuote'), - $sStr - ); - return $sStr; - } - // -------------------------------------------------------------------- /** - * Build quote + * Build str ref link * * @access protected * @param array @@ -889,10 +766,23 @@ * @since coWiki 0.3.0 * * @todo [D11N] Check description - * @todo [D11N] Check return type */ - protected function buildQuote(&$aMatches) { - return "\n<q>\n".trim($aMatches[1])."\n</q>\n"; + protected function buildStrRefLink(&$aMatches) { + if ($aMatches[1] == $aMatches[2] || trim($aMatches[2]) == '') { + if( $aMatches[0] == 'square' ) { + return '[[' . $this->noopDelimiters($aMatches[1]) . ']]'; + } else { + return '((' . $this->noopDelimiters($aMatches[1]) . '))'; + } + } + + if($aMatches[0] == 'square' ) { + return '[[' . $this->noopDelimiters($aMatches[1]) . ']' + .'[' . $aMatches[2] . ']]'; + } else { + return '((' . $this->noopDelimiters($aMatches[1]) . ')' + .'(' . $aMatches[2] . '))'; + } } } // of class