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