1<?php 2if(!defined('DOKU_INC')) die('meh.'); 3require_once DOKU_INC . 'inc/parser/lexer.php'; 4require_once DOKU_INC . 'inc/parser/handler.php'; 5 6 7/** 8 * Define various types of modes used by the parser - they are used to 9 * populate the list of modes another mode accepts 10 */ 11global $PARSER_MODES; 12$PARSER_MODES = array( 13 // containers are complex modes that can contain many other modes 14 // hr breaks the principle but they shouldn't be used in tables / lists 15 // so they are put here 16 'container' => array('listblock','table','quote','hr'), 17 18 // some mode are allowed inside the base mode only 19 'baseonly' => array('header'), 20 21 // modes for styling text -- footnote behaves similar to styling 22 'formatting' => array('strong', 'emphasis', 'underline', 'monospace', 23 'subscript', 'superscript', 'deleted', 'footnote'), 24 25 // modes where the token is simply replaced - they can not contain any 26 // other modes 27 'substition' => array('acronym','smiley','wordblock','entity', 28 'camelcaselink', 'internallink','media', 29 'externallink','linebreak','emaillink', 30 'windowssharelink','filelink','notoc', 31 'nocache','multiplyentity','quotes','rss'), 32 33 // modes which have a start and end token but inside which 34 // no other modes should be applied 35 'protected' => array('preformatted','code','file','php','html','htmlblock','phpblock'), 36 37 // inside this mode no wiki markup should be applied but lineendings 38 // and whitespace isn't preserved 39 'disabled' => array('unformatted'), 40 41 // used to mark paragraph boundaries 42 'paragraphs' => array('eol') 43); 44 45//------------------------------------------------------------------- 46 47/** 48* Sets up the Lexer with modes and points it to the Handler 49* For an intro to the Lexer see: wiki:parser 50*/ 51class Doku_Parser { 52 53 var $Handler; 54 55 /** 56 * @var Doku_Lexer $Lexer 57 */ 58 var $Lexer; 59 60 var $modes = array(); 61 62 var $connected = false; 63 64 function addBaseMode(& $BaseMode) { 65 $this->modes['base'] =& $BaseMode; 66 if ( !$this->Lexer ) { 67 $this->Lexer = new Doku_Lexer($this->Handler,'base', true); 68 } 69 $this->modes['base']->Lexer =& $this->Lexer; 70 } 71 72 /** 73 * PHP preserves order of associative elements 74 * Mode sequence is important 75 */ 76 function addMode($name, & $Mode) { 77 if ( !isset($this->modes['base']) ) { 78 $this->addBaseMode(new Doku_Parser_Mode_base()); 79 } 80 $Mode->Lexer = & $this->Lexer; 81 $this->modes[$name] =& $Mode; 82 } 83 84 function connectModes() { 85 86 if ( $this->connected ) { 87 return; 88 } 89 90 foreach ( array_keys($this->modes) as $mode ) { 91 92 // Base isn't connected to anything 93 if ( $mode == 'base' ) { 94 continue; 95 } 96 $this->modes[$mode]->preConnect(); 97 98 foreach ( array_keys($this->modes) as $cm ) { 99 100 if ( $this->modes[$cm]->accepts($mode) ) { 101 $this->modes[$mode]->connectTo($cm); 102 } 103 104 } 105 106 $this->modes[$mode]->postConnect(); 107 } 108 109 $this->connected = true; 110 } 111 112 function parse($doc) { 113 if ( $this->Lexer ) { 114 $this->connectModes(); 115 // Normalize CRs and pad doc 116 $doc = "\n".str_replace("\r\n","\n",$doc)."\n"; 117 $this->Lexer->parse($doc); 118 $this->Handler->_finalize(); 119 return $this->Handler->calls; 120 } else { 121 return false; 122 } 123 } 124 125} 126 127//------------------------------------------------------------------- 128/** 129 * This class and all the subclasses below are 130 * used to reduce the effort required to register 131 * modes with the Lexer. For performance these 132 * could all be eliminated later perhaps, or 133 * the Parser could be serialized to a file once 134 * all modes are registered 135 * 136 * @author Harry Fuecks <hfuecks@gmail.com> 137*/ 138class Doku_Parser_Mode { 139 140 /** 141 * @var Doku_Lexer $Lexer 142 */ 143 var $Lexer; 144 145 var $allowedModes = array(); 146 147 // returns a number used to determine in which order modes are added 148 function getSort() { 149 trigger_error('getSort() not implemented in '.get_class($this), E_USER_WARNING); 150 } 151 152 // Called before any calls to connectTo 153 function preConnect() {} 154 155 // Connects the mode 156 function connectTo($mode) {} 157 158 // Called after all calls to connectTo 159 function postConnect() {} 160 161 function accepts($mode) { 162 return in_array($mode, (array) $this->allowedModes ); 163 } 164 165} 166 167//------------------------------------------------------------------- 168class Doku_Parser_Mode_base extends Doku_Parser_Mode { 169 170 function Doku_Parser_Mode_base() { 171 global $PARSER_MODES; 172 173 $this->allowedModes = array_merge ( 174 $PARSER_MODES['container'], 175 $PARSER_MODES['baseonly'], 176 $PARSER_MODES['paragraphs'], 177 $PARSER_MODES['formatting'], 178 $PARSER_MODES['substition'], 179 $PARSER_MODES['protected'], 180 $PARSER_MODES['disabled'] 181 ); 182 } 183 184 function getSort() { 185 return 0; 186 } 187} 188 189//------------------------------------------------------------------- 190class Doku_Parser_Mode_footnote extends Doku_Parser_Mode { 191 192 function Doku_Parser_Mode_footnote() { 193 global $PARSER_MODES; 194 195 $this->allowedModes = array_merge ( 196 $PARSER_MODES['container'], 197 $PARSER_MODES['formatting'], 198 $PARSER_MODES['substition'], 199 $PARSER_MODES['protected'], 200 $PARSER_MODES['disabled'] 201 ); 202 203 unset($this->allowedModes[array_search('footnote', $this->allowedModes)]); 204 } 205 206 function connectTo($mode) { 207 $this->Lexer->addEntryPattern( 208 '\x28\x28(?=.*\x29\x29)',$mode,'footnote' 209 ); 210 } 211 212 function postConnect() { 213 $this->Lexer->addExitPattern( 214 '\x29\x29','footnote' 215 ); 216 } 217 218 function getSort() { 219 return 150; 220 } 221} 222 223//------------------------------------------------------------------- 224class Doku_Parser_Mode_header extends Doku_Parser_Mode { 225 226 function connectTo($mode) { 227 //we're not picky about the closing ones, two are enough 228 $this->Lexer->addSpecialPattern( 229 '[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)', 230 $mode, 231 'header' 232 ); 233 } 234 235 function getSort() { 236 return 50; 237 } 238} 239 240//------------------------------------------------------------------- 241class Doku_Parser_Mode_notoc extends Doku_Parser_Mode { 242 243 function connectTo($mode) { 244 $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); 245 } 246 247 function getSort() { 248 return 30; 249 } 250} 251 252//------------------------------------------------------------------- 253class Doku_Parser_Mode_nocache extends Doku_Parser_Mode { 254 255 function connectTo($mode) { 256 $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache'); 257 } 258 259 function getSort() { 260 return 40; 261 } 262} 263 264//------------------------------------------------------------------- 265class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode { 266 267 function connectTo($mode) { 268 $this->Lexer->addSpecialPattern('\x5C{2}(?:[ \t]|(?=\n))',$mode,'linebreak'); 269 } 270 271 function getSort() { 272 return 140; 273 } 274} 275 276//------------------------------------------------------------------- 277class Doku_Parser_Mode_eol extends Doku_Parser_Mode { 278 279 function connectTo($mode) { 280 $badModes = array('listblock','table'); 281 if ( in_array($mode, $badModes) ) { 282 return; 283 } 284 // see FS#1652, pattern extended to swallow preceding whitespace to avoid issues with lines that only contain whitespace 285 $this->Lexer->addSpecialPattern('(?:^[ \t]*)?\n',$mode,'eol'); 286 } 287 288 function getSort() { 289 return 370; 290 } 291} 292 293//------------------------------------------------------------------- 294class Doku_Parser_Mode_hr extends Doku_Parser_Mode { 295 296 function connectTo($mode) { 297 $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr'); 298 } 299 300 function getSort() { 301 return 160; 302 } 303} 304 305//------------------------------------------------------------------- 306/** 307 * This class sets the markup for bold (=strong), 308 * italic (=emphasis), underline etc. 309 */ 310class Doku_Parser_Mode_formatting extends Doku_Parser_Mode { 311 var $type; 312 313 var $formatting = array ( 314 'strong' => array ( 315 'entry'=>'\*\*(?=.*\*\*)', 316 'exit'=>'\*\*', 317 'sort'=>70 318 ), 319 320 'emphasis'=> array ( 321 'entry'=>'//(?=[^\x00]*[^:])', //hack for bugs #384 #763 #1468 322 'exit'=>'//', 323 'sort'=>80 324 ), 325 326 'underline'=> array ( 327 'entry'=>'__(?=.*__)', 328 'exit'=>'__', 329 'sort'=>90 330 ), 331 332 'monospace'=> array ( 333 'entry'=>'\x27\x27(?=.*\x27\x27)', 334 'exit'=>'\x27\x27', 335 'sort'=>100 336 ), 337 338 'subscript'=> array ( 339 'entry'=>'<sub>(?=.*</sub>)', 340 'exit'=>'</sub>', 341 'sort'=>110 342 ), 343 344 'superscript'=> array ( 345 'entry'=>'<sup>(?=.*</sup>)', 346 'exit'=>'</sup>', 347 'sort'=>120 348 ), 349 350 'deleted'=> array ( 351 'entry'=>'<del>(?=.*</del>)', 352 'exit'=>'</del>', 353 'sort'=>130 354 ), 355 ); 356 357 function Doku_Parser_Mode_formatting($type) { 358 global $PARSER_MODES; 359 360 if ( !array_key_exists($type, $this->formatting) ) { 361 trigger_error('Invalid formatting type '.$type, E_USER_WARNING); 362 } 363 364 $this->type = $type; 365 366 // formatting may contain other formatting but not it self 367 $modes = $PARSER_MODES['formatting']; 368 $key = array_search($type, $modes); 369 if ( is_int($key) ) { 370 unset($modes[$key]); 371 } 372 373 $this->allowedModes = array_merge ( 374 $modes, 375 $PARSER_MODES['substition'], 376 $PARSER_MODES['disabled'] 377 ); 378 } 379 380 function connectTo($mode) { 381 382 // Can't nest formatting in itself 383 if ( $mode == $this->type ) { 384 return; 385 } 386 387 $this->Lexer->addEntryPattern( 388 $this->formatting[$this->type]['entry'], 389 $mode, 390 $this->type 391 ); 392 } 393 394 function postConnect() { 395 396 $this->Lexer->addExitPattern( 397 $this->formatting[$this->type]['exit'], 398 $this->type 399 ); 400 401 } 402 403 function getSort() { 404 return $this->formatting[$this->type]['sort']; 405 } 406} 407 408//------------------------------------------------------------------- 409class Doku_Parser_Mode_listblock extends Doku_Parser_Mode { 410 411 function Doku_Parser_Mode_listblock() { 412 global $PARSER_MODES; 413 414 $this->allowedModes = array_merge ( 415 $PARSER_MODES['formatting'], 416 $PARSER_MODES['substition'], 417 $PARSER_MODES['disabled'], 418 $PARSER_MODES['protected'] #XXX new 419 ); 420 421 // $this->allowedModes[] = 'footnote'; 422 } 423 424 function connectTo($mode) { 425 $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock'); 426 $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock'); 427 428 $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); 429 $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); 430 431 } 432 433 function postConnect() { 434 $this->Lexer->addExitPattern('\n','listblock'); 435 } 436 437 function getSort() { 438 return 10; 439 } 440} 441 442//------------------------------------------------------------------- 443class Doku_Parser_Mode_table extends Doku_Parser_Mode { 444 445 function Doku_Parser_Mode_table() { 446 global $PARSER_MODES; 447 448 $this->allowedModes = array_merge ( 449 $PARSER_MODES['formatting'], 450 $PARSER_MODES['substition'], 451 $PARSER_MODES['disabled'], 452 $PARSER_MODES['protected'] 453 ); 454 } 455 456 function connectTo($mode) { 457 $this->Lexer->addEntryPattern('\n\^',$mode,'table'); 458 $this->Lexer->addEntryPattern('\n\|',$mode,'table'); 459 } 460 461 function postConnect() { 462 $this->Lexer->addPattern('\n\^','table'); 463 $this->Lexer->addPattern('\n\|','table'); 464 $this->Lexer->addPattern('[\t ]*:::[\t ]*(?=[\|\^])','table'); 465 $this->Lexer->addPattern('[\t ]+','table'); 466 $this->Lexer->addPattern('\^','table'); 467 $this->Lexer->addPattern('\|','table'); 468 $this->Lexer->addExitPattern('\n','table'); 469 } 470 471 function getSort() { 472 return 60; 473 } 474} 475 476//------------------------------------------------------------------- 477class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode { 478 479 function connectTo($mode) { 480 $this->Lexer->addEntryPattern('<nowiki>(?=.*</nowiki>)',$mode,'unformatted'); 481 $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); 482 } 483 484 function postConnect() { 485 $this->Lexer->addExitPattern('</nowiki>','unformatted'); 486 $this->Lexer->addExitPattern('%%','unformattedalt'); 487 $this->Lexer->mapHandler('unformattedalt','unformatted'); 488 } 489 490 function getSort() { 491 return 170; 492 } 493} 494 495//------------------------------------------------------------------- 496class Doku_Parser_Mode_php extends Doku_Parser_Mode { 497 498 function connectTo($mode) { 499 $this->Lexer->addEntryPattern('<php>(?=.*</php>)',$mode,'php'); 500 $this->Lexer->addEntryPattern('<PHP>(?=.*</PHP>)',$mode,'phpblock'); 501 } 502 503 function postConnect() { 504 $this->Lexer->addExitPattern('</php>','php'); 505 $this->Lexer->addExitPattern('</PHP>','phpblock'); 506 } 507 508 function getSort() { 509 return 180; 510 } 511} 512 513//------------------------------------------------------------------- 514class Doku_Parser_Mode_html extends Doku_Parser_Mode { 515 516 function connectTo($mode) { 517 $this->Lexer->addEntryPattern('<html>(?=.*</html>)',$mode,'html'); 518 $this->Lexer->addEntryPattern('<HTML>(?=.*</HTML>)',$mode,'htmlblock'); 519 } 520 521 function postConnect() { 522 $this->Lexer->addExitPattern('</html>','html'); 523 $this->Lexer->addExitPattern('</HTML>','htmlblock'); 524 } 525 526 function getSort() { 527 return 190; 528 } 529} 530 531//------------------------------------------------------------------- 532class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode { 533 534 function connectTo($mode) { 535 // Has hard coded awareness of lists... 536 $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); 537 $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); 538 539 // How to effect a sub pattern with the Lexer! 540 $this->Lexer->addPattern('\n ','preformatted'); 541 $this->Lexer->addPattern('\n\t','preformatted'); 542 543 } 544 545 function postConnect() { 546 $this->Lexer->addExitPattern('\n','preformatted'); 547 } 548 549 function getSort() { 550 return 20; 551 } 552} 553 554//------------------------------------------------------------------- 555class Doku_Parser_Mode_code extends Doku_Parser_Mode { 556 557 function connectTo($mode) { 558 $this->Lexer->addEntryPattern('<code(?=.*</code>)',$mode,'code'); 559 } 560 561 function postConnect() { 562 $this->Lexer->addExitPattern('</code>','code'); 563 } 564 565 function getSort() { 566 return 200; 567 } 568} 569 570//------------------------------------------------------------------- 571class Doku_Parser_Mode_file extends Doku_Parser_Mode { 572 573 function connectTo($mode) { 574 $this->Lexer->addEntryPattern('<file(?=.*</file>)',$mode,'file'); 575 } 576 577 function postConnect() { 578 $this->Lexer->addExitPattern('</file>','file'); 579 } 580 581 function getSort() { 582 return 210; 583 } 584} 585 586//------------------------------------------------------------------- 587class Doku_Parser_Mode_quote extends Doku_Parser_Mode { 588 589 function Doku_Parser_Mode_quote() { 590 global $PARSER_MODES; 591 592 $this->allowedModes = array_merge ( 593 $PARSER_MODES['formatting'], 594 $PARSER_MODES['substition'], 595 $PARSER_MODES['disabled'], 596 $PARSER_MODES['protected'] #XXX new 597 ); 598 #$this->allowedModes[] = 'footnote'; 599 #$this->allowedModes[] = 'preformatted'; 600 #$this->allowedModes[] = 'unformatted'; 601 } 602 603 function connectTo($mode) { 604 $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); 605 } 606 607 function postConnect() { 608 $this->Lexer->addPattern('\n>{1,}','quote'); 609 $this->Lexer->addExitPattern('\n','quote'); 610 } 611 612 function getSort() { 613 return 220; 614 } 615} 616 617//------------------------------------------------------------------- 618class Doku_Parser_Mode_acronym extends Doku_Parser_Mode { 619 // A list 620 var $acronyms = array(); 621 var $pattern = ''; 622 623 function Doku_Parser_Mode_acronym($acronyms) { 624 usort($acronyms,array($this,'_compare')); 625 $this->acronyms = $acronyms; 626 } 627 628 function preConnect() { 629 if(!count($this->acronyms)) return; 630 631 $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]'; 632 $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms); 633 $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')'; 634 } 635 636 function connectTo($mode) { 637 if(!count($this->acronyms)) return; 638 639 if ( strlen($this->pattern) > 0 ) { 640 $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); 641 } 642 } 643 644 function getSort() { 645 return 240; 646 } 647 648 /** 649 * sort callback to order by string length descending 650 */ 651 function _compare($a,$b) { 652 $a_len = strlen($a); 653 $b_len = strlen($b); 654 if ($a_len > $b_len) { 655 return -1; 656 } else if ($a_len < $b_len) { 657 return 1; 658 } 659 660 return 0; 661 } 662} 663 664//------------------------------------------------------------------- 665class Doku_Parser_Mode_smiley extends Doku_Parser_Mode { 666 // A list 667 var $smileys = array(); 668 var $pattern = ''; 669 670 function Doku_Parser_Mode_smiley($smileys) { 671 $this->smileys = $smileys; 672 } 673 674 function preConnect() { 675 if(!count($this->smileys) || $this->pattern != '') return; 676 677 $sep = ''; 678 foreach ( $this->smileys as $smiley ) { 679 $this->pattern .= $sep.'(?<=\W|^)'.Doku_Lexer_Escape($smiley).'(?=\W|$)'; 680 $sep = '|'; 681 } 682 } 683 684 function connectTo($mode) { 685 if(!count($this->smileys)) return; 686 687 if ( strlen($this->pattern) > 0 ) { 688 $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); 689 } 690 } 691 692 function getSort() { 693 return 230; 694 } 695} 696 697//------------------------------------------------------------------- 698class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode { 699 // A list 700 var $badwords = array(); 701 var $pattern = ''; 702 703 function Doku_Parser_Mode_wordblock($badwords) { 704 $this->badwords = $badwords; 705 } 706 707 function preConnect() { 708 709 if ( count($this->badwords) == 0 || $this->pattern != '') { 710 return; 711 } 712 713 $sep = ''; 714 foreach ( $this->badwords as $badword ) { 715 $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; 716 $sep = '|'; 717 } 718 719 } 720 721 function connectTo($mode) { 722 if ( strlen($this->pattern) > 0 ) { 723 $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); 724 } 725 } 726 727 function getSort() { 728 return 250; 729 } 730} 731 732//------------------------------------------------------------------- 733class Doku_Parser_Mode_entity extends Doku_Parser_Mode { 734 // A list 735 var $entities = array(); 736 var $pattern = ''; 737 738 function Doku_Parser_Mode_entity($entities) { 739 $this->entities = $entities; 740 } 741 742 function preConnect() { 743 if(!count($this->entities) || $this->pattern != '') return; 744 745 $sep = ''; 746 foreach ( $this->entities as $entity ) { 747 $this->pattern .= $sep.Doku_Lexer_Escape($entity); 748 $sep = '|'; 749 } 750 } 751 752 function connectTo($mode) { 753 if(!count($this->entities)) return; 754 755 if ( strlen($this->pattern) > 0 ) { 756 $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity'); 757 } 758 } 759 760 function getSort() { 761 return 260; 762 } 763} 764 765//------------------------------------------------------------------- 766// Implements the 640x480 replacement 767class Doku_Parser_Mode_multiplyentity extends Doku_Parser_Mode { 768 769 function connectTo($mode) { 770 771 $this->Lexer->addSpecialPattern( 772 '(?<=\b)(?:[1-9]|\d{2,})[xX]\d+(?=\b)',$mode,'multiplyentity' 773 ); 774 775 } 776 777 function getSort() { 778 return 270; 779 } 780} 781 782//------------------------------------------------------------------- 783class Doku_Parser_Mode_quotes extends Doku_Parser_Mode { 784 785 function connectTo($mode) { 786 global $conf; 787 788 $ws = '\s/\#~:+=&%@\-\x28\x29\]\[{}><"\''; // whitespace 789 $punc = ';,\.?!'; 790 791 if($conf['typography'] == 2){ 792 $this->Lexer->addSpecialPattern( 793 "(?<=^|[$ws])'(?=[^$ws$punc])",$mode,'singlequoteopening' 794 ); 795 $this->Lexer->addSpecialPattern( 796 "(?<=^|[^$ws]|[$punc])'(?=$|[$ws$punc])",$mode,'singlequoteclosing' 797 ); 798 $this->Lexer->addSpecialPattern( 799 "(?<=^|[^$ws$punc])'(?=$|[^$ws$punc])",$mode,'apostrophe' 800 ); 801 } 802 803 $this->Lexer->addSpecialPattern( 804 "(?<=^|[$ws])\"(?=[^$ws$punc])",$mode,'doublequoteopening' 805 ); 806 $this->Lexer->addSpecialPattern( 807 "\"",$mode,'doublequoteclosing' 808 ); 809 810 811 } 812 813 function getSort() { 814 return 280; 815 } 816} 817 818//------------------------------------------------------------------- 819class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode { 820 821 function connectTo($mode) { 822 $this->Lexer->addSpecialPattern( 823 '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' 824 ); 825 } 826 827 function getSort() { 828 return 290; 829 } 830} 831 832//------------------------------------------------------------------- 833class Doku_Parser_Mode_internallink extends Doku_Parser_Mode { 834 835 function connectTo($mode) { 836 // Word boundaries? 837 $this->Lexer->addSpecialPattern("\[\[(?:(?:[^[\]]*?\[.*?\])|.*?)\]\]",$mode,'internallink'); 838 } 839 840 function getSort() { 841 return 300; 842 } 843} 844 845//------------------------------------------------------------------- 846class Doku_Parser_Mode_media extends Doku_Parser_Mode { 847 848 function connectTo($mode) { 849 // Word boundaries? 850 $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media'); 851 } 852 853 function getSort() { 854 return 320; 855 } 856} 857 858//------------------------------------------------------------------- 859class Doku_Parser_Mode_rss extends Doku_Parser_Mode { 860 861 function connectTo($mode) { 862 $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss'); 863 } 864 865 function getSort() { 866 return 310; 867 } 868} 869 870//------------------------------------------------------------------- 871class Doku_Parser_Mode_externallink extends Doku_Parser_Mode { 872 var $schemes = array(); 873 var $patterns = array(); 874 875 function preConnect() { 876 if(count($this->patterns)) return; 877 878 $ltrs = '\w'; 879 $gunk = '/\#~:.?+=&%@!\-\[\]'; 880 $punc = '.:?\-;,'; 881 $host = $ltrs.$punc; 882 $any = $ltrs.$gunk.$punc; 883 884 $this->schemes = getSchemes(); 885 foreach ( $this->schemes as $scheme ) { 886 $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 887 } 888 889 $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 890 $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 891 } 892 893 function connectTo($mode) { 894 895 foreach ( $this->patterns as $pattern ) { 896 $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); 897 } 898 } 899 900 function getSort() { 901 return 330; 902 } 903} 904 905//------------------------------------------------------------------- 906class Doku_Parser_Mode_filelink extends Doku_Parser_Mode { 907 908 var $pattern; 909 910 function preConnect() { 911 912 $ltrs = '\w'; 913 $gunk = '/\#~:.?+=&%@!\-'; 914 $punc = '.:?\-;,'; 915 $host = $ltrs.$punc; 916 $any = $ltrs.$gunk.$punc; 917 918 $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. 919 $punc.']*[^'.$any.']'; 920 } 921 922 function connectTo($mode) { 923 $this->Lexer->addSpecialPattern( 924 $this->pattern,$mode,'filelink'); 925 } 926 927 function getSort() { 928 return 360; 929 } 930} 931 932//------------------------------------------------------------------- 933class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode { 934 935 var $pattern; 936 937 function preConnect() { 938 $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w-$]+)+"; 939 } 940 941 function connectTo($mode) { 942 $this->Lexer->addSpecialPattern( 943 $this->pattern,$mode,'windowssharelink'); 944 } 945 946 function getSort() { 947 return 350; 948 } 949} 950 951//------------------------------------------------------------------- 952class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode { 953 954 function connectTo($mode) { 955 // pattern below is defined in inc/mail.php 956 $this->Lexer->addSpecialPattern('<'.PREG_PATTERN_VALID_EMAIL.'>',$mode,'emaillink'); 957 } 958 959 function getSort() { 960 return 340; 961 } 962} 963 964 965//Setup VIM: ex: et ts=4 : 966