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