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