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