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