Re: [cowiki-dev] Extension to coWiki text formatting
PAUL HANCHETT <[email protected]>
| Newsgroups | gmane.comp.php.cowiki.devel |
|---|---|
| Message-ID | <[email protected]> |
I think the syntax for plugin needs to change-- It should be <plugin ...
/>. I see no problem with accepting <plugin ... > and changing it to
the proper version.
Should I bug this?
Paul
Archie Campbell wrote:
> Last debugging I'm going to do from my own suggestions. I had a time
> getting ampersands to parse / reparse.
>
> They should be ok with these files... :-)
>
> I'm going to work on the math plugin. Something like this...
>
> <plugin TexMath math="y = x / 2">
>
> It will involve compilation from OCaml source of the tex engine. This
> is a fairly simple operation, but the dependencies are fairly lengthy.
> I quote...
>
> OCaml 3.06 or later is required to compile texvc; this can be acquired
> from http://caml.inria.fr/ if your system doesn't have it available.
> The makefile requires GNU make.
>
> Rasterization is done via LaTeX, dvips, and ImageMagick. These need
> to be installed and in the PATH: latex, dvips, convert
>
> To work properly with rendering non-ASCII Unicode characters, a
> supplemental TeX package is needed (cjk-latex in Debian)
>
> However, the OCaml was easy to hack to remove the first item from the
> texvc TODO file (requiring image transparency), and it should be
> simple to incorporate this widget. texvc is GPL.
>
> I'm going to need a directory for the code (/includes/math) and one
> for output (/cowiki/htdocs/math) ?
>
> >From then on in it's basically a case of using texvc to find its own
> ouput in the htdocs/math directory, named by generated md5 hash of the
> input math formula.
>
> Of course, I'm available for Parser / ReParser bugs at any time.
>
> Regards,
>
> Archie
>
> P.S. I can't get HEAD to run properly. I've provided core.conf
> RESOURCE strings and removed install_pending, but I get nothing from
> index.php or admin.php. Help!
>
> Archie Campbell wrote:
>
>> Er, there were some fairly humourous bugs.
>>
>> And now there aren't.
>>
>> P.S. Until you find some more... ;)
>>
>> Archie Campbell wrote:
>>
>>>Hi there!
>>>
>>>I've refactored the WikiParser and the WikiReverseParser.
>>>
>>>The former parses through a progressive window, and the latter uses the
>>>php xml parser.
>>>
>>>It's quite noticeable how much more condensed the code is, now.
>>>
>>>I've included 'cowikitest.wiki' so that you can see what the parsers are
>>>used to thus far.
>>>
>>>Please break and comment endlessly.
>>>
>>>I'm still aiming to close issues, and here's a candid commentary...
>>>
>>>152 - strikethrough markup. DONE
>>>174 - underline markup. DONE
>>>195 - add <b>, <i>, <u> tags to markup. ON-REQUEST
>>> (should be simple enough, if we tolerate <b> -> ** transformation as
>>>run-of-the-mill)
>>>196 - justification markup. DONE
>>> (er, does <fill> exist in other than dreams?)
>>>198 - lists within table cell. DONE
>>>208 - monospace markup. DONE
>>>
>>>There are doubtless many things I've forgotten, and I know that handing
>>>over a test file is no excuse for documentation, but I'm not in the mood
>>>and it's time for bed. I'll document everything later.
>>>
>>>Oh, just one thing - colorizeQuote in class.Utility.php is failing to
>>>find the COLOR_QUOTE_LEVEL Registry keys, and as a result, <posting>
>>>doesn't do much.
>>>
>>>Regards and good-night.
>>>
>>>Archie
>>>
>>
>> ------------------------------------------------------------------------
>>
>> so we can mail * you a copy immediately. * *
>>
>> * Helping hands: Matt Ho
>> *
>>
>> * * @package parse * @subpackage class * @access public * * @author
>> Daniel T. Gorski, * @copyright (C) Daniel T. Gorski, {@link
>> http://www.develnet.org} * @license
>> http://www.gnu.org/licenses/gpl.html * @version $Revision: 1.36 $ *
>> */ /** * coWiki - Wiki parser class * * @package parse * @subpackage
>> class * @access public * * @author Daniel T. Gorski, * @since coWiki
>> 0.3.0 * @author Archie Campbell * @since coWiki 0.3.5 */ class
>> WikiParser extends Object { protected static $Instance = null;
>> protected $aToc = array(), $aRows = array(), $iRow = 0; protected
>> $aEmph = array(); protected $RefNodes = null; private $snug = 0; //
>> --------------------------------------------------------------------
>> /** * Collect referenced nodes to where the document is linking to *
>> * @access protected * * @author Daniel T. Gorski, * @since coWiki
>> 0.3.0 */ protected function addReferencedNode($Obj) {
>> $this->RefNodes->add($Obj); } //
>> --------------------------------------------------------------------
>> /** * Get referenced nodes * * @access public * * @author Daniel T.
>> Gorski, * @since coWiki 0.3.0 */ public function getReferencedNodes()
>> { return $this->RefNodes; } /** * Get instance * * @access public * *
>> @author Daniel T. Gorski, * @since coWiki 0.3.0 */ public function
>> getInstance() { if (!self::$Instance) { self::$Instance = new
>> WikiParser; } return self::$Instance; } //
>> --------------------------------------------------------------------
>> /** * @access protected * * @author Daniel T. Gorski, * @since coWiki
>> 0.3.0 */ protected function __construct() { $this->resetEmphasis(); }
>> // --- Helper methods
>> ------------------------------------------------- /** * @access
>> protected * * @author Daniel T. Gorski, * @since coWiki 0.3.0 */
>> protected function restoreTokens($sStr){ return $sStr; } /** *
>> Generate "toc" (Document Table of Contents) * * @access protected * *
>> @author Daniel T. Gorski, * @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 =
>> # $this->aToc[$i]['TEXT']; $sStr .= ''; $sStr .= ' '.$sAlias.''; $i++;
>> // Recurse (indent) if toc-entry is nested if
>> (isset($this->aToc[$i]['DEPTH'])) { if ($this->aToc[$i]['DEPTH'] >
>> $nDepth) { $sStr .= '
>>
>> '; $sStr .= $this->buildToc($i, $this->aToc[$i]['DEPTH']);
>> $sStr .= '
>>
>> '; } } $sStr .= '
>> '; } return $sStr; } //
>> --------------------------------------------------------------------
>> /** * parse * * @access public * @param string The wiki source string
>> * @return string Wiki XML * * @author Archie Campbell * @since coWiki
>> 0.3.5 */ public function parse($sStr) { $sRet = ''; $sContent = '';
>> $bList = false; $bTable = false; $bBegin = false; $aList = array();
>> $aTable = array(); // {{{ DEBUG }}} Logger::info('Start parsing wiki
>> document.'); // Init reference collection $this->RefNodes = new
>> Vector; $this->resetEmphasis(); // --- $sStr = trim(escape($sStr));
>> // Replace possible tabulators $sStr = str_replace("\t", ' ', $sStr);
>> // Replace possible \r\n or \n\r with \n $sStr = str_replace("\r\n",
>> "\n", $sStr); $sStr = str_replace("\n\r", "\n", $sStr); $this->aRows
>> = explode( "\n",$sStr."\n" ); $this->iRow = 0; $sRow =
>> $this->aRows[$this->iRow]; $bBegin = true; $t = 0; $l = -1; while(
>> true ) { $sContent = ''; $aMatches = array(); //table of contents
>> alone ^$ if( $bBegin && preg_match( '=^<toc(/?)>$=', $sRow, $aMatches
>> )) { $sRet .= "\n\t\t\n"; //plugins }else if( $bBegin && preg_match(
>> '=^<plugin +([A-Za-z0-9_.]+)( +([^&]*))?>=i', $sRow, $aMatches )) {
>> if(isset($aMatches[3])){ $sRet .= ''; }else{ $sRet .= ''; }
>> //headings }else if( $bBegin && preg_match( '=^(\+{1,})\s*(.*)$=s',
>> $sRow, $aMatches )) { $sContent =
>> $this->processContent($aMatches[2]); if( preg_match( '= ([^<]*)=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 . '';
>> //end of table } else if( $bBegin && ($t > 0) && preg_match(
>> '=^</table>=i', $sRow, $aMatches )) { $sParam = trim($aTable[$t][0]);
>> if( $sParam == '') { $sRet .= "\n".'
>> '.$this->buildTable($aTable[$t]). '
>>
>> '."\n"; } else { $sRet .= "\n".'
>> '. $this->buildTable($aTable[$t]).'
>>
>> '."\n"; } if( --$t == 0 ){ $bTable = false; } //beginning of table }
>> else if( $bBegin && preg_match( '=^<table([^>]*)>$=Ui', $sRow,
>> $aMatches )) { $bTable = true; $aTable[++$t] = array(); array_push(
>> $aTable[$t], $aMatches[1] ); //beginning of list } else if( $bBegin
>> && preg_match( '=^([\s*#]{0,}[*#]) ([^\n]*)$=', $sRow, $aMatches )) {
>> $bList = true; $aList[++$l] = array(); $aList[$l]['TEXT'] =
>> $this->processContent( $aMatches[2] ); $aList[$l]['DEPTH'] = strlen(
>> $aMatches[1] ); $aList[$l]['TYPE'] = (substr($aMatches[1],-1)=='*'?
>> 'ul':'ol'); //horizontal rule } else if ($bBegin && preg_match(
>> '=^-{3,}(\s|$)=', $sRow, $aMatches ) ) { $sRet .= '
>> ------------------------------------------------------------------------
>> '."\n"; /* //noop } else if (preg_match( '=((.*)<noop>)=i', $sRow,
>> $aMatches )) { $sContent = $this->processContent( $aMatches[2], false
>> ) . ''; $sRow = substr( $sRow, strlen($aMatches[1]) ); do { if
>> (preg_match( '=(.*)</noop>=' , $sRow, $aMatches )) { $sContent .=
>> $aMatches[1] . ''; break; } else { $sContent .= $sRow; }
>> if(++$this->iRowaRows)){ $sRow = $this->aRows[$this->iRow]; } else {
>> break; } } while(true); $sRet .= $sContent; */ } else { //end of list
>> if($bList) { $d = 0; $sListType = $aList[$d]['TYPE']; $nDepth =
>> $aList[$d]['DEPTH']; $sContent .= "\n".''. '<'.$sListType.'>'.
>> $this->buildList($d,$nDepth,$aList). ''. ''."\n"; $bList = false;
>> $aList = array(); $l = -1; if($bTable){ array_push( $aTable[$t],
>> $sContent ); }else{ $sRet .= $sContent; } //more table }else
>> if($bTable) { array_push( $aTable[$t], $sRow ); $sRow = ''; //non
>> table/list row }else{ $sContent = $this->processContent( $sRow ); if(
>> $sContent != '' ){ $sRet .= /*'
>>
>> '.*/$sContent/*.'
>>
>> '*/; } $sRow = ''; } } if(isset($aMatches[0])) { $sRow = substr(
>> $sRow, strlen( $aMatches[0] ) ); $bBegin = false; } if ( trim($sRow)
>> == '' ) { if( ++$this->iRow < sizeof($this->aRows) ) { $sRow =
>> $this->aRows[$this->iRow]; $bBegin = true; } else { break; } } } if(
>> preg_match( '=^(.*)\n\t\t\n(.*)$=s', $sRet, $aMatches )) { $t = 0; if
>> (sizeof($this->aToc) > 0) { $sToc = $this->buildToc($t,
>> $this->aToc[$t]['DEPTH']); if ($sToc != '') { $sToc = '
>>
>> ' . $sToc . '
>>
>> '; } else { $sToc = ''; } } return $aMatches[1] . $sToc .
>> $aMatches[2]; } // {{{ DEBUG }}} Logger::info('Finished parsing wiki
>> document.'); return $sRet; } /** * reset Emphasis * * @access
>> protected * * @author Archie Campbell * @since coWiki 0.3.5 */
>> protected function resetEmphasis() { $this->aEmph = array( "b" =>
>> false, "u" => false, "i" => false, "f" => false, "s" => false, "j" =>
>> '', "p" => '' ); } /** * processContent * * @access protected *
>> @return string * * @author Archie Campbell * @since coWiki 0.3.5 */
>> protected function processContent( $sStr ) { $sRet = ''; $aMatches =
>> array(); $this->resetEmphasis(); $sStr = ltrim( $sStr ); while( trim(
>> $sStr ) != '' ) { //noop if (preg_match( '=^<noop>=is', $sStr,
>> $aMatches )) { //greedily munch all until $sStr = substr( $sStr,
>> strlen( $aMatches[0] ) ); $sContent = ''; while( !preg_match(
>> '=^</noop>=is', $sStr, $aMatches ) ) { preg_match(
>> '=([^&]|(\&(?![lg])))*=is', $sStr, $aMatches ); $sContent .=
>> $aMatches[0]; $sStr = substr( $sStr, strlen( $aMatches[0] ) ); if (
>> $sStr == "\n" ) { if ( ++$this->iRow < sizeof($this->aRows) ) { $sStr
>> = $this->aRows[$this->iRow]; } else { $sStr = ''; break; } } } $sRet
>> .= '' . $sContent . ''; //justification } else if( preg_match(
>> '=^<(/?)(left|center|right)>=i', $sStr, $aMatches )) { $sRet .=
>> '<'.$aMatches[1].$aMatches[2].'>'; /* if( $aMatches[1] == '/' &&
>> $this->aEmph['j'] == $aMatches[2]{0} ) { $sRet .= '';
>> $this->aEmph['j'] = ''; } else if ( $aMatches[1] == '' &&
>> $this->aEmph['j'] == '' ) { $sRet .= '<'. $aMatches[2] .'>';
>> $this->aEmph['j'] = $aMatches[2]{0}; } */ //pre code posting q start
>> at BOL, are greedy until // closing tag anywhere on a line } else if
>> (preg_match( '=^<(pre|code|posting|q)>=i', $sStr, $aMatch ) ) { $sStr
>> = substr( $sStr, strlen($aMatch[0]) ); do { if (preg_match(
>> '=(.*)</'.$aMatch[1].'>=i', $sStr, $aMatches )) { $sRet .=
>> '<'.$aMatch[1].'>'.$sContent . $aMatches[1].''; break; } else {
>> $sContent .= $sStr ."\n"; } if( ++$this->iRow < sizeof($this->aRows)
>> ){ $sStr = $this->aRows[$this->iRow]; }else{ break; } } while(true);
>> if( $this->iRow == sizeof($this->aRows) ) { $sRet .=
>> '<'.$aMatch[1].'>'. $sContent . ''; break; } //line-break }else if(
>> preg_match( '=^<br([ /]+)>=is', $sStr, $aMatches )) { $sRet .= '
>> '; //variables }else if( preg_match( '=^%([A-Z0-9_]+)%=U', $sStr,
>> $aMatches )) { $sRet .= ''; //links (()()) & [[][]] }else if(
>> preg_match( '=^\(\(([^\(\)]+|[^\(\)]+' . '\([^\(\)]+\)[^\(\)]*|' .
>> '[^\(\)]+\)\([^\(\)]+)\)\)=Usx', $sStr, $aMatches )) { $sRet .=
>> $this->createLinkElement( $aMatches[1] ); /* $aLink = explode( ')(',
>> $aMatches[1] ); $aLink[0] = str_replace( '|', '¦', $aLink[0] ); $sRet
>> .= ' '; if ( isset( $aLink[1]) ) { $sRet .= trim($aLink[1]); } else {
>> $sRet .= trim($aLink[0]); } $sRet .= ''; */ /* //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 .= ' ' . $sLink . ''; */ /* //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 )) { $sRet
>> .= ''; //subscript, superscript }else if( preg_match(
>> '=^<(/??)(sub|sup)>=is', $sStr, $aMatches ) ) { if( $aMatches[1] ==
>> '/' && $this->aEmph['p'] == $aMatches[2] ) { $sRet .= '';
>> $this->aEmph['p'] = ''; }else if ( $aMatches[1] == '' &&
>> $this->aEmph['p'] == '' ) { $sRet .= '<' . $aMatches[2] . '>';
>> $this->aEmph['p'] = $aMatches[2]; } //emphasis }else if( preg_match(
>> '#^([-=\*_/]{2})#', $sStr, $aMatches ) ) { $sEmph = '';
>> switch($aMatches[1]{0}){ case '-':
>> $sEmph=($this->aEmph["s"]?'/':'').'strike'; $this->aEmph["s"] =
>> !$this->aEmph["s"]; break; case '=':
>> $sEmph=($this->aEmph["f"]?'/':'').'tt'; $this->aEmph["f"] =
>> !$this->aEmph["f"]; break; case '*':
>> $sEmph=($this->aEmph["b"]?'/':'').'b'; $this->aEmph["b"] =
>> !$this->aEmph["b"]; break; case '_':
>> $sEmph=($this->aEmph["u"]?'/':'').'u'; $this->aEmph["u"] =
>> !$this->aEmph["u"]; break; case '/':
>> $sEmph=($this->aEmph["i"]?'/':'').'i'; $this->aEmph["i"] =
>> !$this->aEmph["i"]; break; } $sRet .= '<'.$sEmph.'>'; }else if(
>> preg_match( '#^((([-=\*_/]{1})(?!\3))|[^-=\*_/\&]|(\&(?![lg])))*#',
>> $sStr, $aMatches ) ) { $sRet .= $aMatches[0]; } if(
>> isset($aMatches[0]) ) { $sStr = substr( $sStr, strlen($aMatches[0])
>> ); } } return $sRet; } /** * &build table * * @access protected *
>> @return string * * @author Archie Campbell * @since coWiki 0.3.5 */
>> protected function buildTable( &$aTable ) { $sRet = ''; $sContent =
>> ''; $sRow = ''; $bPriorRow = false; $aMatches = array(); $j = 0; $v =
>> sizeof($aTable); while( ++$j < $v ) { /* if
>> (!strlen(trim($aTable[$j]))) { return ''.$sStr.''; } */ //rows
>> expected to hold table syntax (pipes), may instead //make room for
>> ongoing content (tables, lists, etc) $sRow = $aTable[$j]; //find
>> table syntax within a (long?) row while( strlen($sRow) && preg_match(
>> '=^([\|!][-+]?)( {0,1}[^\|!\n]*)?=', $sRow, $aMatches) ) { //found
>> exploded row begins with pipe syntax, poss params $sRow = substr(
>> $sRow, strlen($aMatches[0]) ); $nType = 0; //tables made of cells,
>> headers, rows, caption if ($aMatches[1]=="|") { $sRet .= '\n";
>> continue 1; } //content can be large, room for it here $sContent =
>> ''; if (isset($aMatches[2]) && $aMatches[2]{0}==' ') { //left a space
>> to denote no params $sRet .= '>'; $sContent .=
>> substr($aMatches[2],1); //expect double pipe, bang or newline }
>> elseif (isset($aMatches[2])) { //got params. look for pipe syntax
>> that blocked last preg $sRet .= ' '.unescape($aMatches[2]).'>'; if
>> (preg_match('=^\|([^\|!\n]*)=',$sRow,$aMatches)) { //got rest of pipe
>> syntax (...|text) $sContent .= $aMatches[1]; $sRow = substr( $sRow,
>> strlen($aMatches[0]) ); } } else { $sRet .= '>'; } //look ahead now.
>> if (trim($sRow) == '') { //look ahead to close our content while(
>> ++$j<$v ){ $sRow = $aTable[$j]; //pipe syntax (will force $sContent)
>> to continue if ($sRow{0} == '|' || $sRow{0} == '!') { $sRet .=
>> $this->processContent($sContent); switch($nType){ case 1: $sRet .=
>> "\n"; break; case 2: $sRet .= "\n"; break; } --$j; continue 3; } else
>> { //non-pipe (ever-increasing) content $sContent .= $sRow; } } $j =
>> $v; $sRet .= $this->processContent($sContent); switch($nType){ case
>> 1: $sRet .= "\n"; break; case 2: $sRet .= "\n"; break; } continue 2;
>> } elseif ( ( $sRow{0} == "|" || $sRow{0} == "!") && ($sRow{1} == "|"
>> || $sRow{1} == "!") ) { $sRow = substr($sRow, 1); $sRet .=
>> $this->processContent($sContent); switch($nType){ case 1: $sRet .=
>> "\n"; break; case 2: $sRet .= "\n"; break; } continue 1; } } } if(
>> $bPriorRow ) { return $sRet.""; } else { return $sRet; } } /** *
>> &build list * * @access protected * @return string * * @author Archie
>> Campbell * @since coWiki 0.3.5 */ protected function buildList(&$i,
>> &$nDepth, &$aList) { $sStr = ''; // Iterate though all list-entries
>> while (isset($aList[$i]['DEPTH']) && $aList[$i]['DEPTH'] == $nDepth)
>> # { $sStr .= ''; $sStr .= $aList[$i]['TEXT']; $i++; // Recurse (indent)
>> if list-entry is nested if (isset($aList[$i]['DEPTH'])) { if
>> ($aList[$i]['DEPTH'] > $nDepth) { // Correct items that are indented
>> too deep $aList[$i]['DEPTH'] = $nDepth + 1; $sListType =
>> $aList[$i]['TYPE']; $sStr .= '<'.$sListType.'>'; $sStr .=
>> $this->buildList( $i, $aList[$i]['DEPTH'], $aList ); $sStr .= ''; } }
>> $sStr .= '
>> '; } return $sStr; } //
>> --------------------------------------------------------------------
>> } // of class /* Prospero: That cross you wear around your neck; is
>> it only a decoration, or are you a true Christian believer?
>> Francesca: Yes, I believe - truly. Prospero: Then I want you to
>> remove it at once! - and never to wear it within this castle again!
>> Do you know how a falcon is trained my dear? Her eyes are sown shut.
>> Blinded temporarily she suffers the whims of her God patiently, until
>> her will is submerged and she learns to serve - as your God taught
>> and blinded you with crosses. Francesca: You had me take off my cross
>> because it offended ... Prospero: It offended no-one. No - it simply
>> appears to me to be discourteous to ... to wear the symbol of a deity
>> long dead. My ancestors tried to find it. And to open the door that
>> seperates us from our Creator. Francesca: But you need no doors to
>> find God. If you believe ... Prospero: Believe?! If you believe you
>> are gullible. Can you look around this world and believe in the
>> goodness of a god who rules it? Famine, Pestilence, War, Disease and
>> Death! They rule this world. Francesca: There is also love and life
>> and hope. Prospero: Very little hope I assure you. No. If a god of
>> love and life ever did exist ... he is long since dead. Someone ...
>> something rules in his place. */ ?>
>> ------------------------------------------------------------------------
>>
>> so we can mail * you a copy immediately. * * @package parse *
>> @subpackage class * @access public * * @author Daniel T. Gorski, *
>> @copyright (C) Daniel T. Gorski, {@link http://www.develnet.org} *
>> @license http://www.gnu.org/licenses/gpl.html * @version $Revision:
>> 1.17 $ * */ /** * coWiki - Wiki reverse parser class * * @package
>> parse * @subpackage class * @access public * * @author Daniel T.
>> Gorski, * @since coWiki 0.3.0 * @author Archie Campbell * @since
>> coWiki 0.3.5 * * @todo [D11N] Complete documentation */ class
>> WikiReverseParser extends Object { protected static $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; //
>> --------------------------------------------------------------------
>> /** * Get instance * * @access public * @return mixed * * @author
>> Daniel T. Gorski, * @since coWiki 0.3.0 * * @todo [D11N] Check
>> description * @todo [D11N] Check return type */ public function
>> getInstance() { if (!self::$Instance) { self::$Instance = new
>> WikiReverseParser; } return self::$Instance; } //
>> --------------------------------------------------------------------
>> /** * Parse * * @access protected * @param string * @return void * *
>> @author Daniel T. Gorski, * @since coWiki 0.3.0 * * @todo [D11N]
>> Check description */ protected function __construct() {
>> $this->Context = RuntimeContext::getInstance(); $this->DocDAO =
>> $this->Context->getDocumentDAO(); } //
>> --------------------------------------------------------------------
>> // FIX: THIS METHOD DO NOT COVER ALL POSSIBLE OCCURANCES OF
>> DELIMITERS // YET! THIS HAS TO BE CHECKED AND FIXED. /** * If a
>> string reference contains delimiters, escape them with * * @access
>> protected * @param string * @return mixed * * @author Daniel T.
>> Gorski, * @since coWiki 0.3.0 * * @todo [D11N] Check return type */
>> protected function noopDelimiters(&$sStr) { // Escape leading
>> delimiters if (substr($sStr, 0, 2) == '()') { $sStr =
>> '<noop>()</noop>'.substr($sStr, 2); } else if (substr($sStr, 0, 1) ==
>> '(') { $sStr = '<noop>(</noop>'. substr($sStr, 1); } // Escape
>> trailing delimiters if (substr($sStr, -2) == '()') { $sStr =
>> substr($sStr, 0, -2).'<noop>()</noop>'; } else if (substr($sStr, -1)
>> == ')') { $sStr = substr($sStr, 0, -1).'<noop>)</noop>'; } // Escape
>> double closing $sStr = str_replace('))', '<noop>))</noop>', $sStr);
>> // Replace web/document delimiter return str_replace('¦', '|',
>> $sStr); } //
>> --------------------------------------------------------------------
>> /** * Helper functions * * @author Archie Campbell * @since coWiki
>> 0.3.5 * */ protected function appendRow($sStr){
>> array_push($this->aRow,$sStr); $this->clearContent(); } protected
>> function clearContent(){ $this->sContent = ''; } protected function
>> clearRow() { if($this->sContent!=''){
>> $this->appendRow($this->sContent); } } protected function
>> textListItem( $sData ) { $this->aList[sizeof($this->aList)-1]['TEXT']
>> .= $sData; } protected function pushTableItem( $sData ) {
>> array_push($this->aTable[sizeof($this->aTable)-1],$sData); } /** *
>> Parse * * @access public * @param string * @return mixed * * @author
>> Archie Campbell * @since coWiki 0.3.5 * */ public function
>> parse($sStr) { //return $this->dummy($sStr); if
>> (!function_exists('xml_parser_create')) { return false; }
>> $this->rParser = @xml_parser_create(); 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); // 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); // Prepare XML, add root element
>> $sStr = '' . $sStr . ''; 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 * @since coWiki 0.3.5 *
>> */ protected function xml_start_handler( &$parser, $sName, $aAttrib )
>> { if($this->ignoreToc){ return; } switch($sName){ case 'document':
>> $this->aRow = array(); break; case 'toc': $this->clearRow();
>> $this->ignoreToc = true; break; case 'plugin': $this->clearRow();
>> $sStr = '1){ foreach($aAttrib as $attr => $value){ if($attr !=
>> 'name'){ $sStr .= ' '.$attr.'='.$value; } } } $sStr .= '>';
>> $this->appendRow($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)){ foreach($aAttrib as $attr => $value){ $sStr .=
>> $attr.'="'.$value.'" '; } } $this->pushTableItem( $sStr ); break;
>> case 'th': array_push($this->aState,9);/*WRP_THED*/ $sStr = '!';
>> if(sizeof($aAttrib)){ foreach($aAttrib as $attr => $value){ $sStr .=
>> $attr.'="'.$value.'" '; } } $sStr .= ' '; $this->pushTableItem( $sStr
>> ); break; case 'td': array_push($this->aState,10);/*WRP_TCEL*/ $sStr
>> = '|'; if(sizeof($aAttrib)){ foreach($aAttrib as $attr => $value){
>> $sStr .= $attr.'="'.$value.'" '; } } $sStr .= ' ';
>> $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: if(strlen($this->sContent)){
>> $this->textListItem($this->sContent); } 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; //noop case 'noop': $this->sContent .= '';
>> array_push($this->aState,5); break; //justification case 'left': case
>> 'right': case 'center': $this->sContent .= '<'.$sName.'>'; break;
>> //pre, code, posting, quote case 'pre': case 'code': case 'posting':
>> case 'q': $this->clearRow(); array_push($this->aState,4); break;
>> //line-break case 'br': $this->clearRow(); 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']; } break; //subscript & superscript case 'sub':
>> case 'sup': $this->sContent .= '<'.$sName.'>'; break; //horizontal
>> rule case 'hr':break; //emphasis (strike,tt,b,u,i) case 'strike':
>> $this->sContent .= "--"; break; case 'tt': $this->sContent .= "==";
>> break; case 'b': $this->sContent .= "**"; break; case 'u':
>> $this->sContent .= "__"; break; case 'i': $this->sContent .= '//';
>> break; default: echo $sName . " start" . "\n"; } } /** * xml element
>> end handler * * @access protected * * @author Archie Campbell *
>> @since coWiki 0.3.5 * */ protected function xml_end_handler(
>> &$parser, $sName ) { if($this->ignoreToc){ if($sName == 'toc'){
>> $this->appendRow(""); $this->ignoreToc = false; return; } }
>> switch($sName){ case 'document': $this->clearRow(); break; case
>> 'plugin': break; //table syntax case 'table':
>> if(array_pop($this->aState)!=6) { echo "insanity in table"; exit; }
>> $aTable = array_pop($this->aTable); $sStr = '
>> $value ){ $sStr .= " ".$attr.'="'.$value.'"'; } $sStr .=
>> (sizeof($aTable)==1?'/>':'>'); $this->appendRow( $sStr ); for ($i =
>> 1; $i < sizeof($aTable) ; $i++){ $this->appendRow( $aTable[$i] ); }
>> $this->appendRow('
>>
>> '); 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; }
>> break; case 'th': if(array_pop($this->aState)!=9) { echo "insanity in
>> thead"; exit; } if($this->sContent != ''){
>> $this->pushTableItem($this->sContent); $this->clearContent(); }
>> break; case 'td': if(array_pop($this->aState)!=10) { echo "insanity
>> in tcell"; exit; } if($this->sContent != ''){
>> $this->pushTableItem($this->sContent); $this->clearContent(); }
>> 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->textListItem($this->sContent); $this->clearContent(); break;
>> //paragraphs case 'p': $this->appendRow( $this->sContent ); break;
>> //noop case 'noop': $this->sContent .= ''; array_pop($this->aState);
>> break; //justification case 'left': case 'right': case 'center':
>> $this->sContent .= ''; break; //pre, code, posting, quote case 'pre':
>> case 'code': case 'posting': case 'q': $this->sContent =
>> '<'.$sName.'>'. $this->sContent. ''; array_pop($this->aState);
>> if(end($this->aState)!=1){ $this->clearRow(); } break; //line-break
>> case 'br': $this->appendRow( '
>> ' ); 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':
>> array_pop($this->aState); $sStr = call_user_func($this->fLink,
>> $this->sLink); $this->sContent .= $sStr; break; //subscript &
>> superscript case 'sub': case 'sup': $this->sContent .= ''; break;
>> //horizontal rule case 'hr': $this->appendRow("---"); break;
>> //emphasis (strike,tt,b,u,i) case 'strike': $this->sContent .= "--";
>> break; case 'tt': $this->sContent .= "=="; break; case 'b':
>> $this->sContent .= "**"; break; case 'u': $this->sContent .= "__";
>> break; case 'i': $this->sContent .= '//'; break; default: echo $sName
>> . " end" . "\n"; } } /** * xml element default handler * * @access
>> protected * * @author Archie Campbell * @since coWiki 0.3.5 * */
>> protected function xml_default_handler( &$parser, $sData ) {
>> if(!$this->ignoreToc){ echo "Don't Panic :" . $sData . "\n"; } } /**
>> * xml cdata handler * * @access protected * * @author Archie Campbell
>> * @since coWiki 0.3.5 * */ protected function xml_cdata_handler(
>> &$parser, $sData ) { if($this->ignoreToc){ return; } if( trim($sData)
>> != '' ) { switch( end($this->aState) ){ case 1:/*WRP_LIST*/ case
>> 3:/*WRP_HEAD*/ case 4:/*WRP_PCPQ*/ case 5:/*WRP_NOOP*/ case
>> 7:/*WRP_CAPT*/ case 9:/*WRP_THED*/ $this->sContent .= $sData; break;
>> case 2:/*WRP_LINK*/ $this->sLink[2]=trim($sData); break;
>> default:/*text*/ $this->sContent .= $sData; } } } //
>> --------------------------------------------------------------------
>> /** * Build str ref link * * @access protected * @param array *
>> @return mixed * * @author Daniel T. Gorski, * @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]) . '))'; } return '((' .
>> $this->noopDelimiters($aMatches[1]) . ')' .'(' . $aMatches[2] . '))';
>> } } // of class ?>
>>
>>------------------------------------------------------------------------
>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: [email protected]
>>For additional commands, e-mail: [email protected]
>>
>
> ------------------------------------------------------------------------
>
> so we can mail * you a copy immediately. * *
>
> * Helping hands: Matt Ho
> *
>
> * * @package parse * @subpackage class * @access public * * @author
> Daniel T. Gorski, * @copyright (C) Daniel T. Gorski, {@link
> http://www.develnet.org} * @license
> http://www.gnu.org/licenses/gpl.html * @version $Revision: 1.36 $ * */
> /** * coWiki - Wiki parser class * * @package parse * @subpackage
> class * @access public * * @author Daniel T. Gorski, * @since coWiki
> 0.3.0 * @author Archie Campbell * @since coWiki 0.3.5 */ class
> WikiParser extends Object { protected static $Instance = null;
> protected $aToc = array(), $aRows = array(), $iRow = 0; protected
> $aEmph = array(); protected $RefNodes = null; private $snug = 0; //
> --------------------------------------------------------------------
> /** * Collect referenced nodes to where the document is linking to * *
> @access protected * * @author Daniel T. Gorski, * @since coWiki 0.3.0
> */ protected function addReferencedNode($Obj) {
> $this->RefNodes->add($Obj); } //
> --------------------------------------------------------------------
> /** * Get referenced nodes * * @access public * * @author Daniel T.
> Gorski, * @since coWiki 0.3.0 */ public function getReferencedNodes()
> { return $this->RefNodes; } /** * Get instance * * @access public * *
> @author Daniel T. Gorski, * @since coWiki 0.3.0 */ public function
> getInstance() { if (!self::$Instance) { self::$Instance = new
> WikiParser; } return self::$Instance; } //
> --------------------------------------------------------------------
> /** * @access protected * * @author Daniel T. Gorski, * @since coWiki
> 0.3.0 */ protected function __construct() { $this->resetEmphasis(); }
> // --- Helper methods
> ------------------------------------------------- /** * @access
> protected * * @author Daniel T. Gorski, * @since coWiki 0.3.0 */
> protected function restoreTokens($sStr){ return $sStr; } /** *
> Generate "toc" (Document Table of Contents) * * @access protected * *
> @author Daniel T. Gorski, * @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 =
> # $this->aToc[$i]['TEXT']; $sStr .= ''; $sStr .= ' '.$sAlias.''; $i++;
> // Recurse (indent) if toc-entry is nested if
> (isset($this->aToc[$i]['DEPTH'])) { if ($this->aToc[$i]['DEPTH'] >
> $nDepth) { $sStr .= '
>
> '; $sStr .= $this->buildToc($i, $this->aToc[$i]['DEPTH']); $sStr
> .= '
>
> '; } } $sStr .= '
> '; } return $sStr; } //
> --------------------------------------------------------------------
> /** * parse * * @access public * @param string The wiki source string
> * @return string Wiki XML * * @author Archie Campbell * @since coWiki
> 0.3.5 */ public function parse($sStr) { $sRet = ''; $sContent = '';
> $bList = false; $bTable = false; $bBegin = false; $aList = array();
> $aTable = array(); // {{{ DEBUG }}} Logger::info('Start parsing wiki
> document.'); // Init reference collection $this->RefNodes = new
> Vector; $this->resetEmphasis(); // --- $sStr = trim(escape($sStr)); //
> Replace possible tabulators $sStr = str_replace("\t", ' ', $sStr); //
> Replace possible \r\n or \n\r with \n $sStr = str_replace("\r\n",
> "\n", $sStr); $sStr = str_replace("\n\r", "\n", $sStr); $this->aRows =
> explode( "\n",$sStr."\n" ); $this->iRow = 0; $sRow =
> $this->aRows[$this->iRow]; $bBegin = true; $t = 0; $l = -1; while(
> true ) { $sContent = ''; $aMatches = array(); //table of contents
> alone ^$ if( $bBegin && preg_match( '=^<toc(/?)>$=', $sRow, $aMatches
> )) { $sRet .= "\n\t\t\n"; //plugins }else if( $bBegin && preg_match(
> '=^<plugin +([A-Za-z0-9_.]+)( +([^&]*))?>=i', $sRow, $aMatches )) {
> if(isset($aMatches[3])){ $sRet .= ''; }else{ $sRet .= ''; } //headings
> }else if( $bBegin && preg_match( '=^(\+{1,})\s*(.*)$=s', $sRow,
> $aMatches )) { $sContent = $this->processContent($aMatches[2]); if(
> preg_match( '= ([^<]*)=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 . ''; //end of table } else if( $bBegin && ($t > 0) &&
> preg_match( '=^</table>=i', $sRow, $aMatches )) { $sParam =
> trim($aTable[$t][0]); if( $sParam == '') { $sRet .= "\n".'
> '.$this->buildTable($aTable[$t]). '
>
> '."\n"; } else { $sRet .= "\n".'
> '. $this->buildTable($aTable[$t]).'
>
> '."\n"; } if( --$t == 0 ){ $bTable = false; } //beginning of table }
> else if( $bBegin && preg_match( '=^<table([^>]*)>$=Ui', $sRow,
> $aMatches )) { $bTable = true; $aTable[++$t] = array(); array_push(
> $aTable[$t], $aMatches[1] ); //beginning of list } else if( $bBegin &&
> preg_match( '=^([\s*#]{0,}[*#]) ([^\n]*)$=', $sRow, $aMatches )) {
> $bList = true; $aList[++$l] = array(); $aList[$l]['TEXT'] =
> $this->processContent( $aMatches[2] ); $aList[$l]['DEPTH'] = strlen(
> $aMatches[1] ); $aList[$l]['TYPE'] = (substr($aMatches[1],-1)=='*'?
> 'ul':'ol'); //horizontal rule } else if ($bBegin && preg_match(
> '=^-{3,}(\s|$)=', $sRow, $aMatches ) ) { $sRet .= '
> ------------------------------------------------------------------------
> '."\n"; /* //noop } else if (preg_match( '=((.*)<noop>)=i', $sRow,
> $aMatches )) { $sContent = $this->processContent( $aMatches[2], false
> ) . ''; $sRow = substr( $sRow, strlen($aMatches[1]) ); do { if
> (preg_match( '=(.*)</noop>=' , $sRow, $aMatches )) { $sContent .=
> $aMatches[1] . ''; break; } else { $sContent .= $sRow; }
> if(++$this->iRowaRows)){ $sRow = $this->aRows[$this->iRow]; } else {
> break; } } while(true); $sRet .= $sContent; */ } else { //end of list
> if($bList) { $d = 0; $sListType = $aList[$d]['TYPE']; $nDepth =
> $aList[$d]['DEPTH']; $sContent .= "\n".''. '<'.$sListType.'>'.
> $this->buildList($d,$nDepth,$aList). ''. ''."\n"; $bList = false;
> $aList = array(); $l = -1; if($bTable){ array_push( $aTable[$t],
> $sContent ); }else{ $sRet .= $sContent; } //more table }else
> if($bTable) { array_push( $aTable[$t], $sRow ); $sRow = ''; //non
> table/list row }else{ $sContent = $this->processContent( $sRow ); if(
> $sContent != '' ){ $sRet .= /*'
>
> '.*/$sContent/*.'
>
> '*/; } $sRow = ''; } } if(isset($aMatches[0])) { $sRow = substr(
> $sRow, strlen( $aMatches[0] ) ); $bBegin = false; } if ( trim($sRow)
> == '' ) { if( ++$this->iRow < sizeof($this->aRows) ) { $sRow =
> $this->aRows[$this->iRow]; $bBegin = true; } else { break; } } } if(
> preg_match( '=^(.*)\n\t\t\n(.*)$=s', $sRet, $aMatches )) { $t = 0; if
> (sizeof($this->aToc) > 0) { $sToc = $this->buildToc($t,
> $this->aToc[$t]['DEPTH']); if ($sToc != '') { $sToc = '
>
> ' . $sToc . '
>
> '; } else { $sToc = ''; } } return $aMatches[1] . $sToc .
> $aMatches[2]; } // {{{ DEBUG }}} Logger::info('Finished parsing wiki
> document.'); return $sRet; } /** * reset Emphasis * * @access
> protected * * @author Archie Campbell * @since coWiki 0.3.5 */
> protected function resetEmphasis() { $this->aEmph = array( "b" =>
> false, "u" => false, "i" => false, "f" => false, "s" => false, "j" =>
> '', "p" => '' ); } /** * processContent * * @access protected *
> @return string * * @author Archie Campbell * @since coWiki 0.3.5 */
> protected function processContent( $sStr ) { $sRet = ''; $aMatches =
> array(); $this->resetEmphasis(); $sStr = ltrim( $sStr ); while( trim(
> $sStr ) != '' ) { //noop if (preg_match( '=^<noop>=is', $sStr,
> $aMatches )) { //greedily munch all until $sStr = substr( $sStr,
> strlen( $aMatches[0] ) ); $sContent = ''; while( !preg_match(
> '=^</noop>=is', $sStr, $aMatches ) ) { preg_match(
> '=([^&]|(\&(?![lg])))*=is', $sStr, $aMatches ); $sContent .=
> $aMatches[0]; $sStr = substr( $sStr, strlen( $aMatches[0] ) ); if (
> $sStr == "\n" ) { if ( ++$this->iRow < sizeof($this->aRows) ) { $sStr
> = $this->aRows[$this->iRow]; } else { $sStr = ''; break; } } } $sRet
> .= '' . $sContent . ''; //justification } else if( preg_match(
> '=^<(/?)(left|center|right)>=i', $sStr, $aMatches )) { $sRet .=
> '<'.$aMatches[1].$aMatches[2].'>'; /* if( $aMatches[1] == '/' &&
> $this->aEmph['j'] == $aMatches[2]{0} ) { $sRet .= '';
> $this->aEmph['j'] = ''; } else if ( $aMatches[1] == '' &&
> $this->aEmph['j'] == '' ) { $sRet .= '<'. $aMatches[2] .'>';
> $this->aEmph['j'] = $aMatches[2]{0}; } */ //pre code posting q start
> at BOL, are greedy until // closing tag anywhere on a line } else if
> (preg_match( '=^<(pre|code|posting|q)>=i', $sStr, $aMatch ) ) { $sStr
> = substr( $sStr, strlen($aMatch[0]) ); do { if (preg_match(
> '=(.*)</'.$aMatch[1].'>=i', $sStr, $aMatches )) { $sRet .=
> '<'.$aMatch[1].'>'.$sContent . $aMatches[1].''; break; } else {
> $sContent .= $sStr ."\n"; } if( ++$this->iRow < sizeof($this->aRows)
> ){ $sStr = $this->aRows[$this->iRow]; }else{ break; } } while(true);
> if( $this->iRow == sizeof($this->aRows) ) { $sRet .=
> '<'.$aMatch[1].'>'. $sContent . ''; break; } //line-break }else if(
> preg_match( '=^<br([ /]+)>=is', $sStr, $aMatches )) { $sRet .= '
> '; //variables }else if( preg_match( '=^%([A-Z0-9_]+)%=U', $sStr,
> $aMatches )) { $sRet .= ''; //links (()()) & [[][]] }else if(
> preg_match( '=^\(\(([^\(\)]+|[^\(\)]+' . '\([^\(\)]+\)[^\(\)]*|' .
> '[^\(\)]+\)\([^\(\)]+)\)\)=Usx', $sStr, $aMatches )) { $sRet .=
> $this->createLinkElement( $aMatches[1] ); /* $aLink = explode( ')(',
> $aMatches[1] ); $aLink[0] = str_replace( '|', '¦', $aLink[0] ); $sRet
> .= ' '; if ( isset( $aLink[1]) ) { $sRet .= trim($aLink[1]); } else {
> $sRet .= trim($aLink[0]); } $sRet .= ''; */ /* //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
> .= ' ' . $sLink . ''; */ /* //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 )) { $sRet
> .= ''; //subscript, superscript }else if( preg_match(
> '=^<(/??)(sub|sup)>=is', $sStr, $aMatches ) ) { if( $aMatches[1] ==
> '/' && $this->aEmph['p'] == $aMatches[2] ) { $sRet .= '';
> $this->aEmph['p'] = ''; }else if ( $aMatches[1] == '' &&
> $this->aEmph['p'] == '' ) { $sRet .= '<' . $aMatches[2] . '>';
> $this->aEmph['p'] = $aMatches[2]; } //emphasis }else if( preg_match(
> '#^([-=\*_/]{2})#', $sStr, $aMatches ) ) { $sEmph = '';
> switch($aMatches[1]{0}){ case '-':
> $sEmph=($this->aEmph["s"]?'/':'').'strike'; $this->aEmph["s"] =
> !$this->aEmph["s"]; break; case '=':
> $sEmph=($this->aEmph["f"]?'/':'').'tt'; $this->aEmph["f"] =
> !$this->aEmph["f"]; break; case '*':
> $sEmph=($this->aEmph["b"]?'/':'').'b'; $this->aEmph["b"] =
> !$this->aEmph["b"]; break; case '_':
> $sEmph=($this->aEmph["u"]?'/':'').'u'; $this->aEmph["u"] =
> !$this->aEmph["u"]; break; case '/':
> $sEmph=($this->aEmph["i"]?'/':'').'i'; $this->aEmph["i"] =
> !$this->aEmph["i"]; break; } $sRet .= '<'.$sEmph.'>'; }else if(
> preg_match( '#^((([-=\*_/]{1})(?!\3))|[^-=\*_/&]|(&(?![lg])))*#',
> $sStr, $aMatches ) ) { $sRet .= $aMatches[0]; } if(
> isset($aMatches[0]) ) { $sStr = substr( $sStr, strlen($aMatches[0]) );
> } } return $sRet; } /** * &build table * * @access protected * @return
> string * * @author Archie Campbell * @since coWiki 0.3.5 */ protected
> function buildTable( &$aTable ) { $sRet = ''; $sContent = ''; $sRow =
> ''; $bPriorRow = false; $aMatches = array(); $j = 0; $v =
> sizeof($aTable); while( ++$j < $v ) { /* if
> (!strlen(trim($aTable[$j]))) { return ''.$sStr.''; } */ //rows
> expected to hold table syntax (pipes), may instead //make room for
> ongoing content (tables, lists, etc) $sRow = $aTable[$j]; //find table
> syntax within a (long?) row while( strlen($sRow) && preg_match(
> '=^([\|!][-+]?)( {0,1}[^\|!\n]*)?=', $sRow, $aMatches) ) { //found
> exploded row begins with pipe syntax, poss params $sRow = substr(
> $sRow, strlen($aMatches[0]) ); $nType = 0; //tables made of cells,
> headers, rows, caption if ($aMatches[1]=="|") { $sRet .= '\n";
> continue 1; } //content can be large, room for it here $sContent = '';
> if (isset($aMatches[2]) && $aMatches[2]{0}==' ') { //left a space to
> denote no params $sRet .= '>'; $sContent .= substr($aMatches[2],1);
> //expect double pipe, bang or newline } elseif (isset($aMatches[2])) {
> //got params. look for pipe syntax that blocked last preg $sRet .= '
> '.unescape($aMatches[2]).'>'; if
> (preg_match('=^\|([^\|!\n]*)=',$sRow,$aMatches)) { //got rest of pipe
> syntax (...|text) $sContent .= $aMatches[1]; $sRow = substr( $sRow,
> strlen($aMatches[0]) ); } } else { $sRet .= '>'; } //look ahead now.
> if (trim($sRow) == '') { //look ahead to close our content while(
> ++$j<$v ){ $sRow = $aTable[$j]; //pipe syntax (will force $sContent)
> to continue if ($sRow{0} == '|' || $sRow{0} == '!') { $sRet .=
> $this->processContent($sContent); switch($nType){ case 1: $sRet .=
> "\n"; break; case 2: $sRet .= "\n"; break; } --$j; continue 3; } else
> { //non-pipe (ever-increasing) content $sContent .= $sRow; } } $j =
> $v; $sRet .= $this->processContent($sContent); switch($nType){ case 1:
> $sRet .= "\n"; break; case 2: $sRet .= "\n"; break; } continue 2; }
> elseif ( ( $sRow{0} == "|" || $sRow{0} == "!") && ($sRow{1} == "|" ||
> $sRow{1} == "!") ) { $sRow = substr($sRow, 1); $sRet .=
> $this->processContent($sContent); switch($nType){ case 1: $sRet .=
> "\n"; break; case 2: $sRet .= "\n"; break; } continue 1; } } } if(
> $bPriorRow ) { return $sRet.""; } else { return $sRet; } } /** *
> &build list * * @access protected * @return string * * @author Archie
> Campbell * @since coWiki 0.3.5 */ protected function buildList(&$i,
> &$nDepth, &$aList) { $sStr = ''; // Iterate though all list-entries
> while (isset($aList[$i]['DEPTH']) && $aList[$i]['DEPTH'] == $nDepth) {
> # $sStr .= ''; $sStr .= $aList[$i]['TEXT']; $i++; // Recurse (indent) if
> list-entry is nested if (isset($aList[$i]['DEPTH'])) { if
> ($aList[$i]['DEPTH'] > $nDepth) { // Correct items that are indented
> too deep $aList[$i]['DEPTH'] = $nDepth + 1; $sListType =
> $aList[$i]['TYPE']; $sStr .= '<'.$sListType.'>'; $sStr .=
> $this->buildList( $i, $aList[$i]['DEPTH'], $aList ); $sStr .= ''; } }
> $sStr .= '
> '; } return $sStr; } //
> -------------------------------------------------------------------- }
> // of class /* Prospero: That cross you wear around your neck; is it
> only a decoration, or are you a true Christian believer? Francesca:
> Yes, I believe - truly. Prospero: Then I want you to remove it at
> once! - and never to wear it within this castle again! Do you know how
> a falcon is trained my dear? Her eyes are sown shut. Blinded
> temporarily she suffers the whims of her God patiently, until her will
> is submerged and she learns to serve - as your God taught and blinded
> you with crosses. Francesca: You had me take off my cross because it
> offended ... Prospero: It offended no-one. No - it simply appears to
> me to be discourteous to ... to wear the symbol of a deity long dead.
> My ancestors tried to find it. And to open the door that seperates us
> from our Creator. Francesca: But you need no doors to find God. If you
> believe ... Prospero: Believe?! If you believe you are gullible. Can
> you look around this world and believe in the goodness of a god who
> rules it? Famine, Pestilence, War, Disease and Death! They rule this
> world. Francesca: There is also love and life and hope. Prospero: Very
> little hope I assure you. No. If a god of love and life ever did exist
> ... he is long since dead. Someone ... something rules in his place.
> */ ?>
> ------------------------------------------------------------------------
>
> so we can mail * you a copy immediately. * * @package parse *
> @subpackage class * @access public * * @author Daniel T. Gorski, *
> @copyright (C) Daniel T. Gorski, {@link http://www.develnet.org} *
> @license http://www.gnu.org/licenses/gpl.html * @version $Revision:
> 1.17 $ * */ /** * coWiki - Wiki reverse parser class * * @package
> parse * @subpackage class * @access public * * @author Daniel T.
> Gorski, * @since coWiki 0.3.0 * @author Archie Campbell * @since
> coWiki 0.3.5 * * @todo [D11N] Complete documentation */ class
> WikiReverseParser extends Object { protected static $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; //
> --------------------------------------------------------------------
> /** * Get instance * * @access public * @return mixed * * @author
> Daniel T. Gorski, * @since coWiki 0.3.0 * * @todo [D11N] Check
> description * @todo [D11N] Check return type */ public function
> getInstance() { if (!self::$Instance) { self::$Instance = new
> WikiReverseParser; } return self::$Instance; } //
> --------------------------------------------------------------------
> /** * Parse * * @access protected * @param string * @return void * *
> @author Daniel T. Gorski, * @since coWiki 0.3.0 * * @todo [D11N] Check
> description */ protected function __construct() { $this->Context =
> RuntimeContext::getInstance(); $this->DocDAO =
> $this->Context->getDocumentDAO(); } //
> --------------------------------------------------------------------
> // FIX: THIS METHOD DO NOT COVER ALL POSSIBLE OCCURANCES OF DELIMITERS
> // YET! THIS HAS TO BE CHECKED AND FIXED. /** * If a string reference
> contains delimiters, escape them with * * @access protected * @param
> string * @return mixed * * @author Daniel T. Gorski, * @since coWiki
> 0.3.0 * * @todo [D11N] Check return type */ protected function
> noopDelimiters(&$sStr) { // Escape leading delimiters if
> (substr($sStr, 0, 2) == '()') { $sStr =
> '<noop>()</noop>'.substr($sStr, 2); } else if (substr($sStr, 0, 1) ==
> '(') { $sStr = '<noop>(</noop>'. substr($sStr, 1); } // Escape
> trailing delimiters if (substr($sStr, -2) == '()') { $sStr =
> substr($sStr, 0, -2).'<noop>()</noop>'; } else if (substr($sStr, -1)
> == ')') { $sStr = substr($sStr, 0, -1).'<noop>)</noop>'; } // Escape
> double closing $sStr = str_replace('))', '<noop>))</noop>', $sStr); //
> Replace web/document delimiter return str_replace('¦', '|', $sStr); }
> //
> --------------------------------------------------------------------
> /** * Helper functions * * @author Archie Campbell * @since coWiki
> 0.3.5 * */ protected function appendRow($sStr){
> array_push($this->aRow,$sStr); $this->clearContent(); } protected
> function clearContent(){ $this->sContent = ''; } protected function
> clearRow() { if($this->sContent!=''){
> $this->appendRow($this->sContent); } } protected function
> textListItem( $sData ) { $this->aList[sizeof($this->aList)-1]['TEXT']
> .= $sData; } protected function pushTableItem( $sData ) {
> array_push($this->aTable[sizeof($this->aTable)-1],$sData); } /** *
> Parse * * @access public * @param string * @return mixed * * @author
> Archie Campbell * @since coWiki 0.3.5 * */ public function
> parse($sStr) { //return $this->dummy($sStr); if
> (!function_exists('xml_parser_create')) { return false; }
> $this->rParser = @xml_parser_create(); 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); // 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); // Prepare XML, add root element
> $sStr = '' . $sStr . ''; 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 * @since coWiki 0.3.5 *
> */ protected function xml_start_handler( &$parser, $sName, $aAttrib )
> { if($this->ignoreToc){ return; } switch($sName){ case 'document':
> $this->aRow = array(); break; case 'toc': $this->clearRow();
> $this->ignoreToc = true; break; case 'plugin': $this->clearRow();
> $sStr = '1){ foreach($aAttrib as $attr => $value){ if($attr !=
> 'name'){ $sStr .= ' '.$attr.'='.$value; } } } $sStr .= '>';
> $this->appendRow($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)){ foreach($aAttrib as $attr => $value){ $sStr .=
> $attr.'="'.$value.'" '; } } $this->pushTableItem( $sStr ); break; case
> 'th': array_push($this->aState,9);/*WRP_THED*/ $sStr = '!';
> if(sizeof($aAttrib)){ foreach($aAttrib as $attr => $value){ $sStr .=
> $attr.'="'.$value.'" '; } } $sStr .= ' '; $this->pushTableItem( $sStr
> ); break; case 'td': array_push($this->aState,10);/*WRP_TCEL*/ $sStr =
> '|'; if(sizeof($aAttrib)){ foreach($aAttrib as $attr => $value){ $sStr
> .= $attr.'="'.$value.'" '; } } $sStr .= ' '; $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: if(strlen($this->sContent)){
> $this->textListItem($this->sContent); } 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; //noop case 'noop': $this->sContent .= '';
> array_push($this->aState,5); break; //justification case 'left': case
> 'right': case 'center': $this->sContent .= '<'.$sName.'>'; break;
> //pre, code, posting, quote case 'pre': case 'code': case 'posting':
> case 'q': $this->clearRow(); array_push($this->aState,4); break;
> //line-break case 'br': $this->clearRow(); 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']; } break; //subscript & superscript case 'sub': case
> 'sup': $this->sContent .= '<'.$sName.'>'; break; //horizontal rule
> case 'hr':break; //emphasis (strike,tt,b,u,i) case 'strike':
> $this->sContent .= "--"; break; case 'tt': $this->sContent .= "==";
> break; case 'b': $this->sContent .= "**"; break; case 'u':
> $this->sContent .= "__"; break; case 'i': $this->sContent .= '//';
> break; default: echo $sName . " start" . "\n"; } } /** * xml element
> end handler * * @access protected * * @author Archie Campbell * @since
> coWiki 0.3.5 * */ protected function xml_end_handler( &$parser, $sName
> ) { if($this->ignoreToc){ if($sName == 'toc'){ $this->appendRow("");
> $this->ignoreToc = false; return; } } switch($sName){ case 'document':
> $this->clearRow(); break; case 'plugin': break; //table syntax case
> 'table': if(array_pop($this->aState)!=6) { echo "insanity in table";
> exit; } $aTable = array_pop($this->aTable); $sStr = '
> $value ){ $sStr .= " ".$attr.'="'.$value.'"'; } $sStr .=
> (sizeof($aTable)==1?'/>':'>'); $this->appendRow( $sStr ); for ($i = 1;
> $i < sizeof($aTable) ; $i++){ $this->appendRow( $aTable[$i] ); }
> $this->appendRow('
>
> '); 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; }
> break; case 'th': if(array_pop($this->aState)!=9) { echo "insanity in
> thead"; exit; } if($this->sContent != ''){
> $this->pushTableItem($this->sContent); $this->clearContent(); } break;
> case 'td': if(array_pop($this->aState)!=10) { echo "insanity in
> tcell"; exit; } if($this->sContent != ''){
> $this->pushTableItem($this->sContent); $this->clearContent(); } 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->textListItem($this->sContent); $this->clearContent(); break;
> //paragraphs case 'p': $this->appendRow( $this->sContent ); break;
> //noop case 'noop': $this->sContent .= ''; array_pop($this->aState);
> break; //justification case 'left': case 'right': case 'center':
> $this->sContent .= ''; break; //pre, code, posting, quote case 'pre':
> case 'code': case 'posting': case 'q': $this->sContent =
> '<'.$sName.'>'. $this->sContent. ''; array_pop($this->aState);
> if(end($this->aState)!=1){ $this->clearRow(); } break; //line-break
> case 'br': $this->appendRow( '
> ' ); 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':
> array_pop($this->aState); $sStr = call_user_func($this->fLink,
> $this->sLink); $this->sContent .= $sStr; break; //subscript &
> superscript case 'sub': case 'sup': $this->sContent .= ''; break;
> //horizontal rule case 'hr': $this->appendRow("---"); break;
> //emphasis (strike,tt,b,u,i) case 'strike': $this->sContent .= "--";
> break; case 'tt': $this->sContent .= "=="; break; case 'b':
> $this->sContent .= "**"; break; case 'u': $this->sContent .= "__";
> break; case 'i': $this->sContent .= '//'; break; default: echo $sName
> . " end" . "\n"; } } /** * xml element default handler * * @access
> protected * * @author Archie Campbell * @since coWiki 0.3.5 * */
> protected function xml_default_handler( &$parser, $sData ) {
> if(!$this->ignoreToc){ $this->sContent .= html_entity_decode($sData);
> } } /** * xml cdata handler * * @access protected * * @author Archie
> Campbell * @since coWiki 0.3.5 * */ protected function
> xml_cdata_handler( &$parser, $sData ) { if($this->ignoreToc){ return;
> } if( trim($sData) != '' ) { switch( end($this->aState) ){ case
> 1:/*WRP_LIST*/ case 3:/*WRP_HEAD*/ case 4:/*WRP_PCPQ*/ case
> 5:/*WRP_NOOP*/ case 7:/*WRP_CAPT*/ case 9:/*WRP_THED*/ $this->sContent
> .= $sData; break; case 2:/*WRP_LINK*/ $this->sLink[2]=trim($sData);
> break; default:/*text*/ $this->sContent .= $sData; } } } //
> --------------------------------------------------------------------
> /** * Build str ref link * * @access protected * @param array *
> @return mixed * * @author Daniel T. Gorski, * @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]) . '))'; } return '((' .
> $this->noopDelimiters($aMatches[1]) . ')' .'(' . $aMatches[2] . '))';
> } } // of class ?>
>
>------------------------------------------------------------------------
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: [email protected]
>For additional commands, e-mail: [email protected]
>