1*0cecf9d5Sandi<?php 2*0cecf9d5Sandi 3*0cecf9d5Sandiif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 4*0cecf9d5Sandi 5*0cecf9d5Sandirequire_once DOKU_INC . 'inc/parser/lexer.php'; 6*0cecf9d5Sandirequire_once DOKU_INC . 'inc/parser/handler.php'; 7*0cecf9d5Sandi 8*0cecf9d5Sandi//------------------------------------------------------------------- 9*0cecf9d5Sandi 10*0cecf9d5Sandi/** 11*0cecf9d5Sandi* Sets up the Lexer with modes and points it to the Handler 12*0cecf9d5Sandi* For an intro to the Lexer see: wiki:parser 13*0cecf9d5Sandi*/ 14*0cecf9d5Sandiclass Doku_Parser { 15*0cecf9d5Sandi 16*0cecf9d5Sandi var $Handler; 17*0cecf9d5Sandi 18*0cecf9d5Sandi var $Lexer; 19*0cecf9d5Sandi 20*0cecf9d5Sandi var $modes = array(); 21*0cecf9d5Sandi 22*0cecf9d5Sandi var $connected = FALSE; 23*0cecf9d5Sandi 24*0cecf9d5Sandi function addBaseMode() { 25*0cecf9d5Sandi $this->modes['base'] = & new Doku_Parser_Mode_Base(); 26*0cecf9d5Sandi if ( !$this->Lexer ) { 27*0cecf9d5Sandi $this->Lexer = & new Doku_Lexer($this->Handler,'base', TRUE); 28*0cecf9d5Sandi } 29*0cecf9d5Sandi $this->modes['base']->Lexer = & $this->Lexer; 30*0cecf9d5Sandi } 31*0cecf9d5Sandi 32*0cecf9d5Sandi /** 33*0cecf9d5Sandi * PHP preserves order of associative elements 34*0cecf9d5Sandi * Mode sequence is important 35*0cecf9d5Sandi */ 36*0cecf9d5Sandi function addMode($name, & $Mode) { 37*0cecf9d5Sandi if ( !isset($this->modes['base']) ) { 38*0cecf9d5Sandi $this->addBaseMode(); 39*0cecf9d5Sandi } 40*0cecf9d5Sandi $Mode->Lexer = & $this->Lexer; 41*0cecf9d5Sandi $this->modes[$name] = & $Mode; 42*0cecf9d5Sandi } 43*0cecf9d5Sandi 44*0cecf9d5Sandi function connectModes() { 45*0cecf9d5Sandi 46*0cecf9d5Sandi if ( $this->connected ) { 47*0cecf9d5Sandi return; 48*0cecf9d5Sandi } 49*0cecf9d5Sandi 50*0cecf9d5Sandi foreach ( array_keys($this->modes) as $mode ) { 51*0cecf9d5Sandi 52*0cecf9d5Sandi // Base isn't connected to anything 53*0cecf9d5Sandi if ( $mode == 'base' ) { 54*0cecf9d5Sandi continue; 55*0cecf9d5Sandi } 56*0cecf9d5Sandi 57*0cecf9d5Sandi $this->modes[$mode]->preConnect(); 58*0cecf9d5Sandi 59*0cecf9d5Sandi foreach ( array_keys($this->modes) as $cm ) { 60*0cecf9d5Sandi 61*0cecf9d5Sandi if ( $this->modes[$cm]->accepts($mode) ) { 62*0cecf9d5Sandi $this->modes[$mode]->connectTo($cm); 63*0cecf9d5Sandi } 64*0cecf9d5Sandi 65*0cecf9d5Sandi } 66*0cecf9d5Sandi 67*0cecf9d5Sandi $this->modes[$mode]->postConnect(); 68*0cecf9d5Sandi } 69*0cecf9d5Sandi 70*0cecf9d5Sandi $this->connected = TRUE; 71*0cecf9d5Sandi } 72*0cecf9d5Sandi 73*0cecf9d5Sandi function parse($doc) { 74*0cecf9d5Sandi if ( $this->Lexer ) { 75*0cecf9d5Sandi $this->connectModes(); 76*0cecf9d5Sandi // Normalize CRs and pad doc 77*0cecf9d5Sandi $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; 78*0cecf9d5Sandi $this->Lexer->parse($doc); 79*0cecf9d5Sandi $this->Handler->__finalize(); 80*0cecf9d5Sandi return $this->Handler->calls; 81*0cecf9d5Sandi } else { 82*0cecf9d5Sandi return FALSE; 83*0cecf9d5Sandi } 84*0cecf9d5Sandi } 85*0cecf9d5Sandi 86*0cecf9d5Sandi} 87*0cecf9d5Sandi 88*0cecf9d5Sandi//------------------------------------------------------------------- 89*0cecf9d5Sandi/** 90*0cecf9d5Sandi* This class and all the subclasses below are 91*0cecf9d5Sandi* used to reduce the effort required to register 92*0cecf9d5Sandi* modes with the Lexer. For performance these 93*0cecf9d5Sandi* could all be eliminated later perhaps, or 94*0cecf9d5Sandi* the Parser could be serialized to a file once 95*0cecf9d5Sandi* all modes are registered 96*0cecf9d5Sandi*/ 97*0cecf9d5Sandiclass Doku_Parser_Mode { 98*0cecf9d5Sandi 99*0cecf9d5Sandi var $Lexer; 100*0cecf9d5Sandi 101*0cecf9d5Sandi var $allowedModes = array(); 102*0cecf9d5Sandi 103*0cecf9d5Sandi // Called before any calls to connectTo 104*0cecf9d5Sandi function preConnect() {} 105*0cecf9d5Sandi 106*0cecf9d5Sandi function connectTo($mode) {} 107*0cecf9d5Sandi 108*0cecf9d5Sandi // Called after all calls to connectTo 109*0cecf9d5Sandi function postConnect() {} 110*0cecf9d5Sandi 111*0cecf9d5Sandi function accepts($mode) { 112*0cecf9d5Sandi return in_array($mode, $this->allowedModes ); 113*0cecf9d5Sandi } 114*0cecf9d5Sandi 115*0cecf9d5Sandi} 116*0cecf9d5Sandi 117*0cecf9d5Sandi//------------------------------------------------------------------- 118*0cecf9d5Sandiclass Doku_Parser_Mode_Base extends Doku_Parser_Mode { 119*0cecf9d5Sandi 120*0cecf9d5Sandi function Doku_Parser_Mode_Base() { 121*0cecf9d5Sandi 122*0cecf9d5Sandi $this->allowedModes = array_merge ( 123*0cecf9d5Sandi Doku_Parser_BlockContainers(), 124*0cecf9d5Sandi Doku_Parser_BaseOnly(), 125*0cecf9d5Sandi Doku_Parser_Paragraphs(), 126*0cecf9d5Sandi Doku_Parser_Formatting(), 127*0cecf9d5Sandi Doku_Parser_Substition(), 128*0cecf9d5Sandi Doku_Parser_Protected(), 129*0cecf9d5Sandi Doku_Parser_Disabled() 130*0cecf9d5Sandi ); 131*0cecf9d5Sandi } 132*0cecf9d5Sandi} 133*0cecf9d5Sandi 134*0cecf9d5Sandi//------------------------------------------------------------------- 135*0cecf9d5Sandiclass Doku_Parser_Mode_Footnote extends Doku_Parser_Mode { 136*0cecf9d5Sandi 137*0cecf9d5Sandi function Doku_Parser_Mode_Footnote() { 138*0cecf9d5Sandi 139*0cecf9d5Sandi $this->allowedModes = array_merge ( 140*0cecf9d5Sandi Doku_Parser_BlockContainers(), 141*0cecf9d5Sandi Doku_Parser_Formatting(), 142*0cecf9d5Sandi Doku_Parser_Substition(), 143*0cecf9d5Sandi Doku_Parser_Protected(), 144*0cecf9d5Sandi Doku_Parser_Disabled() 145*0cecf9d5Sandi ); 146*0cecf9d5Sandi 147*0cecf9d5Sandi } 148*0cecf9d5Sandi 149*0cecf9d5Sandi function connectTo($mode) { 150*0cecf9d5Sandi $this->Lexer->addEntryPattern( 151*0cecf9d5Sandi '\x28\x28(?=.*\x29\x29)',$mode,'footnote' 152*0cecf9d5Sandi ); 153*0cecf9d5Sandi } 154*0cecf9d5Sandi 155*0cecf9d5Sandi function postConnect() { 156*0cecf9d5Sandi $this->Lexer->addExitPattern( 157*0cecf9d5Sandi '\x29\x29','footnote' 158*0cecf9d5Sandi ); 159*0cecf9d5Sandi 160*0cecf9d5Sandi } 161*0cecf9d5Sandi 162*0cecf9d5Sandi} 163*0cecf9d5Sandi 164*0cecf9d5Sandi//------------------------------------------------------------------- 165*0cecf9d5Sandiclass Doku_Parser_Mode_Header extends Doku_Parser_Mode { 166*0cecf9d5Sandi 167*0cecf9d5Sandi function preConnect() { 168*0cecf9d5Sandi 169*0cecf9d5Sandi // Header 1 is special case - match 6 or more 170*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 171*0cecf9d5Sandi '[ \t]*={6,}[^\n]+={6,}[ \t]*\n', 172*0cecf9d5Sandi 'base', 173*0cecf9d5Sandi 'header' 174*0cecf9d5Sandi ); 175*0cecf9d5Sandi 176*0cecf9d5Sandi // For the rest, match exactly 177*0cecf9d5Sandi for ( $i = 5; $i > 1; $i--) { 178*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 179*0cecf9d5Sandi '[ \t]*={'.$i.'}[^\n]+={'.$i.'}[ \t]*\n', 180*0cecf9d5Sandi 'base', 181*0cecf9d5Sandi 'header' 182*0cecf9d5Sandi ); 183*0cecf9d5Sandi } 184*0cecf9d5Sandi } 185*0cecf9d5Sandi 186*0cecf9d5Sandi} 187*0cecf9d5Sandi 188*0cecf9d5Sandi//------------------------------------------------------------------- 189*0cecf9d5Sandiclass Doku_Parser_Mode_NoToc extends Doku_Parser_Mode { 190*0cecf9d5Sandi 191*0cecf9d5Sandi function connectTo($mode) { 192*0cecf9d5Sandi $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); 193*0cecf9d5Sandi } 194*0cecf9d5Sandi 195*0cecf9d5Sandi} 196*0cecf9d5Sandi 197*0cecf9d5Sandi//------------------------------------------------------------------- 198*0cecf9d5Sandiclass Doku_Parser_Mode_Linebreak extends Doku_Parser_Mode { 199*0cecf9d5Sandi 200*0cecf9d5Sandi function connectTo($mode) { 201*0cecf9d5Sandi $this->Lexer->addSpecialPattern('\x5C{2}\s',$mode,'linebreak'); 202*0cecf9d5Sandi } 203*0cecf9d5Sandi} 204*0cecf9d5Sandi 205*0cecf9d5Sandi//------------------------------------------------------------------- 206*0cecf9d5Sandiclass Doku_Parser_Mode_Eol extends Doku_Parser_Mode { 207*0cecf9d5Sandi 208*0cecf9d5Sandi function connectTo($mode) { 209*0cecf9d5Sandi $badModes = array('listblock','table'); 210*0cecf9d5Sandi if ( in_array($mode, $badModes) ) { 211*0cecf9d5Sandi return; 212*0cecf9d5Sandi } 213*0cecf9d5Sandi $this->Lexer->addSpecialPattern('\n',$mode,'eol'); 214*0cecf9d5Sandi } 215*0cecf9d5Sandi} 216*0cecf9d5Sandi 217*0cecf9d5Sandi//------------------------------------------------------------------- 218*0cecf9d5Sandiclass Doku_Parser_Mode_HR extends Doku_Parser_Mode { 219*0cecf9d5Sandi 220*0cecf9d5Sandi function connectTo($mode) { 221*0cecf9d5Sandi $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*\n',$mode,'hr'); 222*0cecf9d5Sandi } 223*0cecf9d5Sandi 224*0cecf9d5Sandi} 225*0cecf9d5Sandi 226*0cecf9d5Sandi//------------------------------------------------------------------- 227*0cecf9d5Sandiclass Doku_Parser_Mode_Formatting extends Doku_Parser_Mode { 228*0cecf9d5Sandi 229*0cecf9d5Sandi var $type; 230*0cecf9d5Sandi 231*0cecf9d5Sandi var $formatting = array ( 232*0cecf9d5Sandi 'strong' => array ( 233*0cecf9d5Sandi 'entry'=>'\*\*(?=.*\*\*)', 234*0cecf9d5Sandi 'exit'=>'\*\*', 235*0cecf9d5Sandi ), 236*0cecf9d5Sandi 237*0cecf9d5Sandi 'emphasis'=> array ( 238*0cecf9d5Sandi 'entry'=>'//(?=.*//)', 239*0cecf9d5Sandi 'exit'=>'//', 240*0cecf9d5Sandi ), 241*0cecf9d5Sandi 242*0cecf9d5Sandi 'underline'=> array ( 243*0cecf9d5Sandi 'entry'=>'__(?=.*__)', 244*0cecf9d5Sandi 'exit'=>'__', 245*0cecf9d5Sandi ), 246*0cecf9d5Sandi 247*0cecf9d5Sandi 'monospace'=> array ( 248*0cecf9d5Sandi 'entry'=>'\x27\x27(?=.*\x27\x27)', 249*0cecf9d5Sandi 'exit'=>'\x27\x27', 250*0cecf9d5Sandi ), 251*0cecf9d5Sandi 252*0cecf9d5Sandi 'subscript'=> array ( 253*0cecf9d5Sandi 'entry'=>'<sub>(?=.*\x3C/sub\x3E)', 254*0cecf9d5Sandi 'exit'=>'</sub>', 255*0cecf9d5Sandi ), 256*0cecf9d5Sandi 257*0cecf9d5Sandi 'superscript'=> array ( 258*0cecf9d5Sandi 'entry'=>'<sup>(?=.*\x3C/sup\x3E)', 259*0cecf9d5Sandi 'exit'=>'</sup>', 260*0cecf9d5Sandi ), 261*0cecf9d5Sandi 262*0cecf9d5Sandi 'deleted'=> array ( 263*0cecf9d5Sandi 'entry'=>'<del>(?=.*\x3C/del\x3E)', 264*0cecf9d5Sandi 'exit'=>'</del>', 265*0cecf9d5Sandi ), 266*0cecf9d5Sandi ); 267*0cecf9d5Sandi 268*0cecf9d5Sandi function Doku_Parser_Mode_Formatting($type) { 269*0cecf9d5Sandi 270*0cecf9d5Sandi if ( !array_key_exists($type, $this->formatting) ) { 271*0cecf9d5Sandi trigger_error('Invalid formatting type '.$type, E_USER_WARNING); 272*0cecf9d5Sandi } 273*0cecf9d5Sandi 274*0cecf9d5Sandi $this->type = $type; 275*0cecf9d5Sandi 276*0cecf9d5Sandi $this->allowedModes = array_merge ( 277*0cecf9d5Sandi Doku_Parser_Formatting($type), 278*0cecf9d5Sandi Doku_Parser_Substition(), 279*0cecf9d5Sandi Doku_Parser_Disabled() 280*0cecf9d5Sandi ); 281*0cecf9d5Sandi 282*0cecf9d5Sandi } 283*0cecf9d5Sandi 284*0cecf9d5Sandi function connectTo($mode) { 285*0cecf9d5Sandi 286*0cecf9d5Sandi // Can't nest formatting in itself 287*0cecf9d5Sandi if ( $mode == $this->type ) { 288*0cecf9d5Sandi return; 289*0cecf9d5Sandi } 290*0cecf9d5Sandi 291*0cecf9d5Sandi $this->Lexer->addEntryPattern( 292*0cecf9d5Sandi $this->formatting[$this->type]['entry'], 293*0cecf9d5Sandi $mode, 294*0cecf9d5Sandi $this->type 295*0cecf9d5Sandi ); 296*0cecf9d5Sandi } 297*0cecf9d5Sandi 298*0cecf9d5Sandi function postConnect() { 299*0cecf9d5Sandi 300*0cecf9d5Sandi $this->Lexer->addExitPattern( 301*0cecf9d5Sandi $this->formatting[$this->type]['exit'], 302*0cecf9d5Sandi $this->type 303*0cecf9d5Sandi ); 304*0cecf9d5Sandi 305*0cecf9d5Sandi } 306*0cecf9d5Sandi} 307*0cecf9d5Sandi 308*0cecf9d5Sandi//------------------------------------------------------------------- 309*0cecf9d5Sandiclass Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode { 310*0cecf9d5Sandi 311*0cecf9d5Sandi function Doku_Parser_Mode_ListBlock() { 312*0cecf9d5Sandi 313*0cecf9d5Sandi $this->allowedModes = array_merge ( 314*0cecf9d5Sandi Doku_Parser_Formatting(), 315*0cecf9d5Sandi Doku_Parser_Substition(), 316*0cecf9d5Sandi Doku_Parser_Disabled() 317*0cecf9d5Sandi ); 318*0cecf9d5Sandi $this->allowedModes[] = 'footnote'; 319*0cecf9d5Sandi $this->allowedModes[] = 'preformatted'; 320*0cecf9d5Sandi $this->allowedModes[] = 'unformatted'; 321*0cecf9d5Sandi 322*0cecf9d5Sandi } 323*0cecf9d5Sandi 324*0cecf9d5Sandi function connectTo($mode) { 325*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock'); 326*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock'); 327*0cecf9d5Sandi 328*0cecf9d5Sandi $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); 329*0cecf9d5Sandi $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); 330*0cecf9d5Sandi 331*0cecf9d5Sandi } 332*0cecf9d5Sandi 333*0cecf9d5Sandi function postConnect() { 334*0cecf9d5Sandi $this->Lexer->addExitPattern('\n','listblock'); 335*0cecf9d5Sandi } 336*0cecf9d5Sandi} 337*0cecf9d5Sandi 338*0cecf9d5Sandi//------------------------------------------------------------------- 339*0cecf9d5Sandiclass Doku_Parser_Mode_Table extends Doku_Parser_Mode { 340*0cecf9d5Sandi 341*0cecf9d5Sandi function Doku_Parser_Mode_Table() { 342*0cecf9d5Sandi 343*0cecf9d5Sandi $this->allowedModes = array_merge ( 344*0cecf9d5Sandi Doku_Parser_Formatting(), 345*0cecf9d5Sandi Doku_Parser_Substition(), 346*0cecf9d5Sandi Doku_Parser_Disabled() 347*0cecf9d5Sandi ); 348*0cecf9d5Sandi $this->allowedModes[] = 'footnote'; 349*0cecf9d5Sandi $this->allowedModes[] = 'preformatted'; 350*0cecf9d5Sandi $this->allowedModes[] = 'unformatted'; 351*0cecf9d5Sandi } 352*0cecf9d5Sandi 353*0cecf9d5Sandi function connectTo($mode) { 354*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n\^',$mode,'table'); 355*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n\|',$mode,'table'); 356*0cecf9d5Sandi } 357*0cecf9d5Sandi 358*0cecf9d5Sandi function postConnect() { 359*0cecf9d5Sandi $this->Lexer->addPattern('\n\^','table'); 360*0cecf9d5Sandi $this->Lexer->addPattern('\n\|','table'); 361*0cecf9d5Sandi $this->Lexer->addPattern(' {2,}','table'); 362*0cecf9d5Sandi $this->Lexer->addPattern('\^','table'); 363*0cecf9d5Sandi $this->Lexer->addPattern('\|','table'); 364*0cecf9d5Sandi $this->Lexer->addExitPattern('\n','table'); 365*0cecf9d5Sandi } 366*0cecf9d5Sandi} 367*0cecf9d5Sandi 368*0cecf9d5Sandi//------------------------------------------------------------------- 369*0cecf9d5Sandiclass Doku_Parser_Mode_Unformatted extends Doku_Parser_Mode { 370*0cecf9d5Sandi 371*0cecf9d5Sandi function connectTo($mode) { 372*0cecf9d5Sandi $this->Lexer->addEntryPattern('<nowiki>(?=.*\x3C/nowiki\x3E)',$mode,'unformatted'); 373*0cecf9d5Sandi $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); 374*0cecf9d5Sandi } 375*0cecf9d5Sandi 376*0cecf9d5Sandi function postConnect() { 377*0cecf9d5Sandi $this->Lexer->addExitPattern('</nowiki>','unformatted'); 378*0cecf9d5Sandi $this->Lexer->addExitPattern('%%','unformattedalt'); 379*0cecf9d5Sandi $this->Lexer->mapHandler('unformattedalt','unformatted'); 380*0cecf9d5Sandi } 381*0cecf9d5Sandi 382*0cecf9d5Sandi} 383*0cecf9d5Sandi 384*0cecf9d5Sandi//------------------------------------------------------------------- 385*0cecf9d5Sandiclass Doku_Parser_Mode_PHP extends Doku_Parser_Mode { 386*0cecf9d5Sandi 387*0cecf9d5Sandi function connectTo($mode) { 388*0cecf9d5Sandi $this->Lexer->addEntryPattern('<php>(?=.*\x3C/php\x3E)',$mode,'php'); 389*0cecf9d5Sandi } 390*0cecf9d5Sandi 391*0cecf9d5Sandi function postConnect() { 392*0cecf9d5Sandi $this->Lexer->addExitPattern('</php>','php'); 393*0cecf9d5Sandi } 394*0cecf9d5Sandi 395*0cecf9d5Sandi} 396*0cecf9d5Sandi 397*0cecf9d5Sandi//------------------------------------------------------------------- 398*0cecf9d5Sandiclass Doku_Parser_Mode_HTML extends Doku_Parser_Mode { 399*0cecf9d5Sandi 400*0cecf9d5Sandi function connectTo($mode) { 401*0cecf9d5Sandi $this->Lexer->addEntryPattern('<html>(?=.*\x3C/html\x3E)',$mode,'html'); 402*0cecf9d5Sandi } 403*0cecf9d5Sandi 404*0cecf9d5Sandi function postConnect() { 405*0cecf9d5Sandi $this->Lexer->addExitPattern('</html>','html'); 406*0cecf9d5Sandi } 407*0cecf9d5Sandi 408*0cecf9d5Sandi} 409*0cecf9d5Sandi 410*0cecf9d5Sandi//------------------------------------------------------------------- 411*0cecf9d5Sandiclass Doku_Parser_Mode_Preformatted extends Doku_Parser_Mode { 412*0cecf9d5Sandi 413*0cecf9d5Sandi function connectTo($mode) { 414*0cecf9d5Sandi // Has hard coded awareness of lists... 415*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); 416*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); 417*0cecf9d5Sandi 418*0cecf9d5Sandi // How to effect a sub pattern with the Lexer! 419*0cecf9d5Sandi $this->Lexer->addPattern('\n ','preformatted'); 420*0cecf9d5Sandi $this->Lexer->addPattern('\n\t','preformatted'); 421*0cecf9d5Sandi 422*0cecf9d5Sandi } 423*0cecf9d5Sandi 424*0cecf9d5Sandi function postConnect() { 425*0cecf9d5Sandi $this->Lexer->addExitPattern('\n','preformatted'); 426*0cecf9d5Sandi } 427*0cecf9d5Sandi 428*0cecf9d5Sandi} 429*0cecf9d5Sandi 430*0cecf9d5Sandi//------------------------------------------------------------------- 431*0cecf9d5Sandiclass Doku_Parser_Mode_Code extends Doku_Parser_Mode { 432*0cecf9d5Sandi 433*0cecf9d5Sandi function connectTo($mode) { 434*0cecf9d5Sandi $this->Lexer->addEntryPattern('<code(?=.*\x3C/code\x3E)',$mode,'code'); 435*0cecf9d5Sandi } 436*0cecf9d5Sandi 437*0cecf9d5Sandi function postConnect() { 438*0cecf9d5Sandi $this->Lexer->addExitPattern('</code>','code'); 439*0cecf9d5Sandi } 440*0cecf9d5Sandi 441*0cecf9d5Sandi} 442*0cecf9d5Sandi 443*0cecf9d5Sandi//------------------------------------------------------------------- 444*0cecf9d5Sandiclass Doku_Parser_Mode_File extends Doku_Parser_Mode { 445*0cecf9d5Sandi 446*0cecf9d5Sandi function connectTo($mode) { 447*0cecf9d5Sandi $this->Lexer->addEntryPattern('<file>(?=.*\x3C/file\x3E)',$mode,'file'); 448*0cecf9d5Sandi } 449*0cecf9d5Sandi 450*0cecf9d5Sandi function postConnect() { 451*0cecf9d5Sandi $this->Lexer->addExitPattern('</file>','file'); 452*0cecf9d5Sandi } 453*0cecf9d5Sandi 454*0cecf9d5Sandi} 455*0cecf9d5Sandi 456*0cecf9d5Sandi//------------------------------------------------------------------- 457*0cecf9d5Sandiclass Doku_Parser_Mode_Quote extends Doku_Parser_Mode { 458*0cecf9d5Sandi 459*0cecf9d5Sandi function Doku_Parser_Mode_Quote() { 460*0cecf9d5Sandi 461*0cecf9d5Sandi $this->allowedModes = array_merge ( 462*0cecf9d5Sandi Doku_Parser_Formatting(), 463*0cecf9d5Sandi Doku_Parser_Substition(), 464*0cecf9d5Sandi Doku_Parser_Disabled() 465*0cecf9d5Sandi ); 466*0cecf9d5Sandi $this->allowedModes[] = 'footnote'; 467*0cecf9d5Sandi $this->allowedModes[] = 'preformatted'; 468*0cecf9d5Sandi $this->allowedModes[] = 'unformatted'; 469*0cecf9d5Sandi } 470*0cecf9d5Sandi 471*0cecf9d5Sandi function connectTo($mode) { 472*0cecf9d5Sandi $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); 473*0cecf9d5Sandi } 474*0cecf9d5Sandi 475*0cecf9d5Sandi function postConnect() { 476*0cecf9d5Sandi $this->Lexer->addPattern('\n>{1,}','quote'); 477*0cecf9d5Sandi $this->Lexer->addExitPattern('\n','quote'); 478*0cecf9d5Sandi } 479*0cecf9d5Sandi 480*0cecf9d5Sandi} 481*0cecf9d5Sandi 482*0cecf9d5Sandi//------------------------------------------------------------------- 483*0cecf9d5Sandiclass Doku_Parser_Mode_Acronym extends Doku_Parser_Mode { 484*0cecf9d5Sandi // A list 485*0cecf9d5Sandi var $acronyms = array(); 486*0cecf9d5Sandi var $pattern = ''; 487*0cecf9d5Sandi 488*0cecf9d5Sandi function Doku_Parser_Mode_Acronym($acronyms) { 489*0cecf9d5Sandi $this->acronyms = $acronyms; 490*0cecf9d5Sandi } 491*0cecf9d5Sandi 492*0cecf9d5Sandi function preConnect() { 493*0cecf9d5Sandi $sep = ''; 494*0cecf9d5Sandi foreach ( $this->acronyms as $acronym ) { 495*0cecf9d5Sandi $this->pattern .= $sep.'(?<=\b)'.Doku_Lexer_Escape($acronym).'(?=\b)'; 496*0cecf9d5Sandi $sep = '|'; 497*0cecf9d5Sandi } 498*0cecf9d5Sandi } 499*0cecf9d5Sandi 500*0cecf9d5Sandi function connectTo($mode) { 501*0cecf9d5Sandi if ( strlen($this->pattern) > 0 ) { 502*0cecf9d5Sandi $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); 503*0cecf9d5Sandi } 504*0cecf9d5Sandi } 505*0cecf9d5Sandi 506*0cecf9d5Sandi} 507*0cecf9d5Sandi 508*0cecf9d5Sandi//------------------------------------------------------------------- 509*0cecf9d5Sandiclass Doku_Parser_Mode_Smiley extends Doku_Parser_Mode { 510*0cecf9d5Sandi // A list 511*0cecf9d5Sandi var $smileys = array(); 512*0cecf9d5Sandi var $pattern = ''; 513*0cecf9d5Sandi 514*0cecf9d5Sandi function Doku_Parser_Mode_Smiley($smileys) { 515*0cecf9d5Sandi $this->smileys = $smileys; 516*0cecf9d5Sandi } 517*0cecf9d5Sandi 518*0cecf9d5Sandi function preConnect() { 519*0cecf9d5Sandi $sep = ''; 520*0cecf9d5Sandi foreach ( $this->smileys as $smiley ) { 521*0cecf9d5Sandi $this->pattern .= $sep.Doku_Lexer_Escape($smiley); 522*0cecf9d5Sandi $sep = '|'; 523*0cecf9d5Sandi } 524*0cecf9d5Sandi } 525*0cecf9d5Sandi 526*0cecf9d5Sandi function connectTo($mode) { 527*0cecf9d5Sandi if ( strlen($this->pattern) > 0 ) { 528*0cecf9d5Sandi $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); 529*0cecf9d5Sandi } 530*0cecf9d5Sandi } 531*0cecf9d5Sandi 532*0cecf9d5Sandi} 533*0cecf9d5Sandi 534*0cecf9d5Sandi//------------------------------------------------------------------- 535*0cecf9d5Sandiclass Doku_Parser_Mode_Wordblock extends Doku_Parser_Mode { 536*0cecf9d5Sandi // A list 537*0cecf9d5Sandi var $badwords = array(); 538*0cecf9d5Sandi var $pattern = ''; 539*0cecf9d5Sandi 540*0cecf9d5Sandi function Doku_Parser_Mode_Wordblock($badwords) { 541*0cecf9d5Sandi $this->badwords = $badwords; 542*0cecf9d5Sandi } 543*0cecf9d5Sandi 544*0cecf9d5Sandi function preConnect() { 545*0cecf9d5Sandi 546*0cecf9d5Sandi if ( count($this->badwords) == 0 ) { 547*0cecf9d5Sandi return; 548*0cecf9d5Sandi } 549*0cecf9d5Sandi 550*0cecf9d5Sandi $sep = ''; 551*0cecf9d5Sandi foreach ( $this->badwords as $badword ) { 552*0cecf9d5Sandi $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; 553*0cecf9d5Sandi $sep = '|'; 554*0cecf9d5Sandi } 555*0cecf9d5Sandi 556*0cecf9d5Sandi } 557*0cecf9d5Sandi 558*0cecf9d5Sandi function connectTo($mode) { 559*0cecf9d5Sandi if ( strlen($this->pattern) > 0 ) { 560*0cecf9d5Sandi $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); 561*0cecf9d5Sandi } 562*0cecf9d5Sandi } 563*0cecf9d5Sandi 564*0cecf9d5Sandi} 565*0cecf9d5Sandi 566*0cecf9d5Sandi//------------------------------------------------------------------- 567*0cecf9d5Sandi/** 568*0cecf9d5Sandi* @TODO Quotes and 640x480 are note supported - just straight replacements here 569*0cecf9d5Sandi*/ 570*0cecf9d5Sandiclass Doku_Parser_Mode_Entity extends Doku_Parser_Mode { 571*0cecf9d5Sandi // A list 572*0cecf9d5Sandi var $entities = array(); 573*0cecf9d5Sandi var $pattern = ''; 574*0cecf9d5Sandi 575*0cecf9d5Sandi function Doku_Parser_Mode_Entity($entities) { 576*0cecf9d5Sandi $this->entities = $entities; 577*0cecf9d5Sandi } 578*0cecf9d5Sandi 579*0cecf9d5Sandi function preConnect() { 580*0cecf9d5Sandi $sep = ''; 581*0cecf9d5Sandi foreach ( $this->entities as $entity ) { 582*0cecf9d5Sandi $this->pattern .= $sep.Doku_Lexer_Escape($entity); 583*0cecf9d5Sandi $sep = '|'; 584*0cecf9d5Sandi } 585*0cecf9d5Sandi } 586*0cecf9d5Sandi 587*0cecf9d5Sandi function connectTo($mode) { 588*0cecf9d5Sandi if ( strlen($this->pattern) > 0 ) { 589*0cecf9d5Sandi $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity'); 590*0cecf9d5Sandi } 591*0cecf9d5Sandi } 592*0cecf9d5Sandi 593*0cecf9d5Sandi} 594*0cecf9d5Sandi 595*0cecf9d5Sandi//------------------------------------------------------------------- 596*0cecf9d5Sandi// Implements the 640x480 replacement 597*0cecf9d5Sandiclass Doku_Parser_Mode_MultiplyEntity extends Doku_Parser_Mode { 598*0cecf9d5Sandi 599*0cecf9d5Sandi function connectTo($mode) { 600*0cecf9d5Sandi 601*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 602*0cecf9d5Sandi '(?<=\b)\d+[x|X]\d+(?=\b)',$mode,'multiplyentity' 603*0cecf9d5Sandi ); 604*0cecf9d5Sandi 605*0cecf9d5Sandi } 606*0cecf9d5Sandi 607*0cecf9d5Sandi} 608*0cecf9d5Sandi 609*0cecf9d5Sandi//------------------------------------------------------------------- 610*0cecf9d5Sandiclass Doku_Parser_Mode_Quotes extends Doku_Parser_Mode { 611*0cecf9d5Sandi 612*0cecf9d5Sandi function connectTo($mode) { 613*0cecf9d5Sandi 614*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 615*0cecf9d5Sandi '(?<=\s)\'(?=\S)',$mode,'singlequoteopening' 616*0cecf9d5Sandi ); 617*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 618*0cecf9d5Sandi '(?<=\S)\'',$mode,'singlequoteclosing' 619*0cecf9d5Sandi ); 620*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 621*0cecf9d5Sandi '(?<=\s)"(?=\S)',$mode,'doublequoteopening' 622*0cecf9d5Sandi ); 623*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 624*0cecf9d5Sandi '(?<=\S)"',$mode,'doublequoteclosing' 625*0cecf9d5Sandi ); 626*0cecf9d5Sandi 627*0cecf9d5Sandi } 628*0cecf9d5Sandi 629*0cecf9d5Sandi} 630*0cecf9d5Sandi 631*0cecf9d5Sandi//------------------------------------------------------------------- 632*0cecf9d5Sandiclass Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode { 633*0cecf9d5Sandi 634*0cecf9d5Sandi function connectTo($mode) { 635*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 636*0cecf9d5Sandi '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' 637*0cecf9d5Sandi ); 638*0cecf9d5Sandi } 639*0cecf9d5Sandi 640*0cecf9d5Sandi} 641*0cecf9d5Sandi 642*0cecf9d5Sandi//------------------------------------------------------------------- 643*0cecf9d5Sandiclass Doku_Parser_Mode_InternalLink extends Doku_Parser_Mode { 644*0cecf9d5Sandi 645*0cecf9d5Sandi function connectTo($mode) { 646*0cecf9d5Sandi // Word boundaries? 647*0cecf9d5Sandi $this->Lexer->addSpecialPattern("\[\[[^\]]+?\]\]",$mode,'internallink'); 648*0cecf9d5Sandi } 649*0cecf9d5Sandi 650*0cecf9d5Sandi} 651*0cecf9d5Sandi 652*0cecf9d5Sandi//------------------------------------------------------------------- 653*0cecf9d5Sandiclass Doku_Parser_Mode_Media extends Doku_Parser_Mode { 654*0cecf9d5Sandi 655*0cecf9d5Sandi function connectTo($mode) { 656*0cecf9d5Sandi // Word boundaries? 657*0cecf9d5Sandi $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media'); 658*0cecf9d5Sandi } 659*0cecf9d5Sandi 660*0cecf9d5Sandi} 661*0cecf9d5Sandi 662*0cecf9d5Sandi//------------------------------------------------------------------- 663*0cecf9d5Sandiclass Doku_Parser_Mode_ExternalLink extends Doku_Parser_Mode { 664*0cecf9d5Sandi var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc'); 665*0cecf9d5Sandi var $patterns = array(); 666*0cecf9d5Sandi 667*0cecf9d5Sandi function preConnect() { 668*0cecf9d5Sandi 669*0cecf9d5Sandi $ltrs = '\w'; 670*0cecf9d5Sandi $gunk = '/\#~:.?+=&%@!\-'; 671*0cecf9d5Sandi $punc = '.:?\-;,'; 672*0cecf9d5Sandi $host = $ltrs.$punc; 673*0cecf9d5Sandi $any = $ltrs.$gunk.$punc; 674*0cecf9d5Sandi 675*0cecf9d5Sandi foreach ( $this->schemes as $scheme ) { 676*0cecf9d5Sandi $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?['.$punc.']*[^'.$any.']'; 677*0cecf9d5Sandi } 678*0cecf9d5Sandi 679*0cecf9d5Sandi $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?['.$punc.']*[^'.$any.']'; 680*0cecf9d5Sandi $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?['.$punc.']*[^'.$any.']'; 681*0cecf9d5Sandi 682*0cecf9d5Sandi } 683*0cecf9d5Sandi 684*0cecf9d5Sandi function connectTo($mode) { 685*0cecf9d5Sandi foreach ( $this->patterns as $pattern ) { 686*0cecf9d5Sandi $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); 687*0cecf9d5Sandi } 688*0cecf9d5Sandi } 689*0cecf9d5Sandi 690*0cecf9d5Sandi} 691*0cecf9d5Sandi 692*0cecf9d5Sandi//------------------------------------------------------------------- 693*0cecf9d5Sandiclass Doku_Parser_Mode_FileLink extends Doku_Parser_Mode { 694*0cecf9d5Sandi 695*0cecf9d5Sandi var $pattern; 696*0cecf9d5Sandi 697*0cecf9d5Sandi function preConnect() { 698*0cecf9d5Sandi 699*0cecf9d5Sandi $ltrs = '\w'; 700*0cecf9d5Sandi $gunk = '/\#~:.?+=&%@!\-'; 701*0cecf9d5Sandi $punc = '.:?\-;,'; 702*0cecf9d5Sandi $host = $ltrs.$punc; 703*0cecf9d5Sandi $any = $ltrs.$gunk.$punc; 704*0cecf9d5Sandi 705*0cecf9d5Sandi $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. 706*0cecf9d5Sandi $punc.']*[^'.$any.']'; 707*0cecf9d5Sandi } 708*0cecf9d5Sandi 709*0cecf9d5Sandi function connectTo($mode) { 710*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 711*0cecf9d5Sandi $this->pattern,$mode,'filelink'); 712*0cecf9d5Sandi } 713*0cecf9d5Sandi 714*0cecf9d5Sandi 715*0cecf9d5Sandi} 716*0cecf9d5Sandi 717*0cecf9d5Sandi//------------------------------------------------------------------- 718*0cecf9d5Sandiclass Doku_Parser_Mode_WindowsShareLink extends Doku_Parser_Mode { 719*0cecf9d5Sandi 720*0cecf9d5Sandi var $pattern; 721*0cecf9d5Sandi 722*0cecf9d5Sandi function preConnect() { 723*0cecf9d5Sandi 724*0cecf9d5Sandi $ltrs = '\w'; 725*0cecf9d5Sandi $gunk = '/\#~:.?+=&%@!\-'; 726*0cecf9d5Sandi $punc = '.:?\-;,'; 727*0cecf9d5Sandi $host = $ltrs.$punc; 728*0cecf9d5Sandi $any = $ltrs.$gunk.$punc; 729*0cecf9d5Sandi 730*0cecf9d5Sandi $this->pattern = "[$gunk$punc\s]\\\\\\\\[$host]+?\\\\[$any]+?[$punc]*[^$any]"; 731*0cecf9d5Sandi } 732*0cecf9d5Sandi 733*0cecf9d5Sandi function connectTo($mode) { 734*0cecf9d5Sandi $this->Lexer->addSpecialPattern( 735*0cecf9d5Sandi $this->pattern,$mode,'windowssharelink'); 736*0cecf9d5Sandi } 737*0cecf9d5Sandi 738*0cecf9d5Sandi 739*0cecf9d5Sandi} 740*0cecf9d5Sandi 741*0cecf9d5Sandi//------------------------------------------------------------------- 742*0cecf9d5Sandiclass Doku_Parser_Mode_Email extends Doku_Parser_Mode { 743*0cecf9d5Sandi 744*0cecf9d5Sandi function connectTo($mode) { 745*0cecf9d5Sandi //<([\w0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)> 746*0cecf9d5Sandi $this->Lexer->addSpecialPattern("<[\w0-9\-_.]+?@[\w\-]+\.[\w\-\.]+\.*[\w]+>",$mode,'email'); 747*0cecf9d5Sandi } 748*0cecf9d5Sandi 749*0cecf9d5Sandi} 750*0cecf9d5Sandi 751*0cecf9d5Sandi//------------------------------------------------------------------- 752*0cecf9d5Sandi// Help fns to keep mode lists - used to make it easier to populate 753*0cecf9d5Sandi// the list of modes another mode accepts 754*0cecf9d5Sandi 755*0cecf9d5Sandi// Can contain many other modes 756*0cecf9d5Sandi// E.g. a footnote can containing formatting etc. 757*0cecf9d5Sandifunction Doku_Parser_BlockContainers() { 758*0cecf9d5Sandi $modes = array( 759*0cecf9d5Sandi 'footnote', 'listblock', 'table','quote', 760*0cecf9d5Sandi // hr breaks the principle but HRs should not be used in tables / lists 761*0cecf9d5Sandi // so put it here 762*0cecf9d5Sandi 'hr', 763*0cecf9d5Sandi ); 764*0cecf9d5Sandi return $modes; 765*0cecf9d5Sandi} 766*0cecf9d5Sandi 767*0cecf9d5Sandi// Used to mark paragraph boundaries 768*0cecf9d5Sandifunction Doku_Parser_Paragraphs() { 769*0cecf9d5Sandi $modes = array( 770*0cecf9d5Sandi 'eol' 771*0cecf9d5Sandi ); 772*0cecf9d5Sandi return $modes; 773*0cecf9d5Sandi} 774*0cecf9d5Sandi 775*0cecf9d5Sandi// Can only be used by the base mode 776*0cecf9d5Sandifunction Doku_Parser_BaseOnly() { 777*0cecf9d5Sandi $modes = array( 778*0cecf9d5Sandi 'header' 779*0cecf9d5Sandi ); 780*0cecf9d5Sandi return $modes; 781*0cecf9d5Sandi} 782*0cecf9d5Sandi 783*0cecf9d5Sandi// "Styling" modes that format text. 784*0cecf9d5Sandifunction Doku_Parser_Formatting($remove = '') { 785*0cecf9d5Sandi $modes = array( 786*0cecf9d5Sandi 'strong', 'emphasis', 'underline', 'monospace', 787*0cecf9d5Sandi 'subscript', 'superscript', 'deleted', 788*0cecf9d5Sandi ); 789*0cecf9d5Sandi $key = array_search($remove, $modes); 790*0cecf9d5Sandi if ( is_int($key) ) { 791*0cecf9d5Sandi unset($modes[$key]); 792*0cecf9d5Sandi } 793*0cecf9d5Sandi 794*0cecf9d5Sandi return $modes; 795*0cecf9d5Sandi} 796*0cecf9d5Sandi 797*0cecf9d5Sandi// Modes where the token is simply replaced - contain no 798*0cecf9d5Sandi// other modes 799*0cecf9d5Sandifunction Doku_Parser_Substition() { 800*0cecf9d5Sandi $modes = array( 801*0cecf9d5Sandi 'acronym','smiley','wordblock','entity','camelcaselink', 802*0cecf9d5Sandi 'internallink','media','externallink','linebreak','email', 803*0cecf9d5Sandi 'windowssharelink','filelink','notoc','multiplyentity', 804*0cecf9d5Sandi 'quotes', 805*0cecf9d5Sandi 806*0cecf9d5Sandi ); 807*0cecf9d5Sandi return $modes; 808*0cecf9d5Sandi} 809*0cecf9d5Sandi 810*0cecf9d5Sandi// Modes which have a start and end token but inside which 811*0cecf9d5Sandi// no other modes should be applied 812*0cecf9d5Sandifunction Doku_Parser_Protected() { 813*0cecf9d5Sandi $modes = array( 814*0cecf9d5Sandi 'preformatted','code','file', 815*0cecf9d5Sandi 'php','html','quote', 816*0cecf9d5Sandi ); 817*0cecf9d5Sandi return $modes; 818*0cecf9d5Sandi} 819*0cecf9d5Sandi 820*0cecf9d5Sandi// Disable wiki markup inside this mode 821*0cecf9d5Sandifunction Doku_Parser_Disabled() { 822*0cecf9d5Sandi $modes = array( 823*0cecf9d5Sandi 'unformatted' 824*0cecf9d5Sandi ); 825*0cecf9d5Sandi return $modes; 826*0cecf9d5Sandi} 827*0cecf9d5Sandi 828*0cecf9d5Sandi?> 829