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 } 201 202 function connectTo($mode) { 203 $this->Lexer->addEntryPattern( 204 '\x28\x28(?=.*\x29\x29)',$mode,'footnote' 205 ); 206 } 207 208 function postConnect() { 209 $this->Lexer->addExitPattern( 210 '\x29\x29','footnote' 211 ); 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 226 // Header 1 is special case - match 6 or more 227 $this->Lexer->addSpecialPattern( 228 '[ \t]*={6,}[^\n]+={2,}[ \t]*(?=\n)', 229 'base', 230 'header' 231 ); 232 233 // For the rest, match exactly 234 for ( $i = 5; $i > 1; $i--) { 235 $this->Lexer->addSpecialPattern( 236 '[ \t]*={'.$i.'}[^\n]+={2,}[ \t]*(?=\n)', 237 'base', 238 'header' 239 ); 240 } 241 } 242 243 function getSort() { 244 return 50; 245 } 246} 247 248//------------------------------------------------------------------- 249class Doku_Parser_Mode_notoc extends Doku_Parser_Mode { 250 251 function connectTo($mode) { 252 $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc'); 253 } 254 255 function getSort() { 256 return 30; 257 } 258} 259 260//------------------------------------------------------------------- 261class Doku_Parser_Mode_nocache extends Doku_Parser_Mode { 262 263 function connectTo($mode) { 264 $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache'); 265 } 266 267 function getSort() { 268 return 40; 269 } 270} 271 272//------------------------------------------------------------------- 273class Doku_Parser_Mode_linebreak extends Doku_Parser_Mode { 274 275 function connectTo($mode) { 276 $this->Lexer->addSpecialPattern('\x5C{2}(?=\s)',$mode,'linebreak'); 277 } 278 279 function getSort() { 280 return 140; 281 } 282} 283 284//------------------------------------------------------------------- 285class Doku_Parser_Mode_eol extends Doku_Parser_Mode { 286 287 function connectTo($mode) { 288 $badModes = array('listblock','table'); 289 if ( in_array($mode, $badModes) ) { 290 return; 291 } 292 $this->Lexer->addSpecialPattern('\n',$mode,'eol'); 293 } 294 295 function getSort() { 296 return 370; 297 } 298} 299 300//------------------------------------------------------------------- 301class Doku_Parser_Mode_hr extends Doku_Parser_Mode { 302 303 function connectTo($mode) { 304 $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr'); 305 } 306 307 function getSort() { 308 return 160; 309 } 310} 311 312//------------------------------------------------------------------- 313class Doku_Parser_Mode_formatting extends Doku_Parser_Mode { 314 var $type; 315 316 var $formatting = array ( 317 'strong' => array ( 318 'entry'=>'\*\*(?=.*\*\*)', 319 'exit'=>'\*\*', 320 'sort'=>70 321 ), 322 323 'emphasis'=> array ( 324 'entry'=>'//(?=[^\x00]*[^:]//)', //hack for bug #384 325 'exit'=>'//', 326 'sort'=>80 327 ), 328 329 'underline'=> array ( 330 'entry'=>'__(?=.*__)', 331 'exit'=>'__', 332 'sort'=>90 333 ), 334 335 'monospace'=> array ( 336 'entry'=>'\x27\x27(?=.*\x27\x27)', 337 'exit'=>'\x27\x27', 338 'sort'=>100 339 ), 340 341 'subscript'=> array ( 342 'entry'=>'<sub>(?=.*\x3C/sub\x3E)', 343 'exit'=>'</sub>', 344 'sort'=>110 345 ), 346 347 'superscript'=> array ( 348 'entry'=>'<sup>(?=.*\x3C/sup\x3E)', 349 'exit'=>'</sup>', 350 'sort'=>120 351 ), 352 353 'deleted'=> array ( 354 'entry'=>'<del>(?=.*\x3C/del\x3E)', 355 'exit'=>'</del>', 356 'sort'=>130 357 ), 358 ); 359 360 function Doku_Parser_Mode_formatting($type) { 361 global $PARSER_MODES; 362 363 if ( !array_key_exists($type, $this->formatting) ) { 364 trigger_error('Invalid formatting type '.$type, E_USER_WARNING); 365 } 366 367 $this->type = $type; 368 369 // formatting may contain other formatting but not it self 370 $modes = $PARSER_MODES['formatting']; 371 $key = array_search($type, $modes); 372 if ( is_int($key) ) { 373 unset($modes[$key]); 374 } 375 376 $this->allowedModes = array_merge ( 377 $modes, 378 $PARSER_MODES['substition'], 379 $PARSER_MODES['disabled'] 380 ); 381 } 382 383 function connectTo($mode) { 384 385 // Can't nest formatting in itself 386 if ( $mode == $this->type ) { 387 return; 388 } 389 390 $this->Lexer->addEntryPattern( 391 $this->formatting[$this->type]['entry'], 392 $mode, 393 $this->type 394 ); 395 } 396 397 function postConnect() { 398 399 $this->Lexer->addExitPattern( 400 $this->formatting[$this->type]['exit'], 401 $this->type 402 ); 403 404 } 405 406 function getSort() { 407 return $this->formatting[$this->type]['sort']; 408 } 409} 410 411//------------------------------------------------------------------- 412class Doku_Parser_Mode_listblock extends Doku_Parser_Mode { 413 414 function Doku_Parser_Mode_listblock() { 415 global $PARSER_MODES; 416 417 $this->allowedModes = array_merge ( 418 $PARSER_MODES['formatting'], 419 $PARSER_MODES['substition'], 420 $PARSER_MODES['disabled'], 421 $PARSER_MODES['protected'] #XXX new 422 ); 423 424 // $this->allowedModes[] = 'footnote'; 425 } 426 427 function connectTo($mode) { 428 $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock'); 429 $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock'); 430 431 $this->Lexer->addPattern('\n {2,}[\-\*]','listblock'); 432 $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock'); 433 434 } 435 436 function postConnect() { 437 $this->Lexer->addExitPattern('\n','listblock'); 438 } 439 440 function getSort() { 441 return 10; 442 } 443} 444 445//------------------------------------------------------------------- 446class Doku_Parser_Mode_table extends Doku_Parser_Mode { 447 448 function Doku_Parser_Mode_table() { 449 global $PARSER_MODES; 450 451 $this->allowedModes = array_merge ( 452 $PARSER_MODES['formatting'], 453 $PARSER_MODES['substition'], 454 $PARSER_MODES['disabled'], 455 $PARSER_MODES['protected'] 456 ); 457 } 458 459 function connectTo($mode) { 460 $this->Lexer->addEntryPattern('\n\^',$mode,'table'); 461 $this->Lexer->addEntryPattern('\n\|',$mode,'table'); 462 } 463 464 function postConnect() { 465 $this->Lexer->addPattern('\n\^','table'); 466 $this->Lexer->addPattern('\n\|','table'); 467 #$this->Lexer->addPattern(' {2,}','table'); 468 $this->Lexer->addPattern('[\t ]+','table'); 469 $this->Lexer->addPattern('\^','table'); 470 $this->Lexer->addPattern('\|','table'); 471 $this->Lexer->addExitPattern('\n','table'); 472 } 473 474 function getSort() { 475 return 60; 476 } 477} 478 479//------------------------------------------------------------------- 480class Doku_Parser_Mode_unformatted extends Doku_Parser_Mode { 481 482 function connectTo($mode) { 483 $this->Lexer->addEntryPattern('<nowiki>(?=.*\x3C/nowiki\x3E)',$mode,'unformatted'); 484 $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt'); 485 } 486 487 function postConnect() { 488 $this->Lexer->addExitPattern('</nowiki>','unformatted'); 489 $this->Lexer->addExitPattern('%%','unformattedalt'); 490 $this->Lexer->mapHandler('unformattedalt','unformatted'); 491 } 492 493 function getSort() { 494 return 170; 495 } 496} 497 498//------------------------------------------------------------------- 499class Doku_Parser_Mode_php extends Doku_Parser_Mode { 500 501 function connectTo($mode) { 502 $this->Lexer->addEntryPattern('<php>(?=.*\x3C/php\x3E)',$mode,'php'); 503 } 504 505 function postConnect() { 506 $this->Lexer->addExitPattern('</php>','php'); 507 } 508 509 function getSort() { 510 return 180; 511 } 512} 513 514//------------------------------------------------------------------- 515class Doku_Parser_Mode_html extends Doku_Parser_Mode { 516 517 function connectTo($mode) { 518 $this->Lexer->addEntryPattern('<html>(?=.*\x3C/html\x3E)',$mode,'html'); 519 } 520 521 function postConnect() { 522 $this->Lexer->addExitPattern('</html>','html'); 523 } 524 525 function getSort() { 526 return 190; 527 } 528} 529 530//------------------------------------------------------------------- 531class Doku_Parser_Mode_preformatted extends Doku_Parser_Mode { 532 533 function connectTo($mode) { 534 // Has hard coded awareness of lists... 535 $this->Lexer->addEntryPattern('\n (?![\*\-])',$mode,'preformatted'); 536 $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted'); 537 538 // How to effect a sub pattern with the Lexer! 539 $this->Lexer->addPattern('\n ','preformatted'); 540 $this->Lexer->addPattern('\n\t','preformatted'); 541 542 } 543 544 function postConnect() { 545 $this->Lexer->addExitPattern('\n','preformatted'); 546 } 547 548 function getSort() { 549 return 20; 550 } 551} 552 553//------------------------------------------------------------------- 554class Doku_Parser_Mode_code extends Doku_Parser_Mode { 555 556 function connectTo($mode) { 557 $this->Lexer->addEntryPattern('<code(?=.*\x3C/code\x3E)',$mode,'code'); 558 } 559 560 function postConnect() { 561 $this->Lexer->addExitPattern('</code>','code'); 562 } 563 564 function getSort() { 565 return 200; 566 } 567} 568 569//------------------------------------------------------------------- 570class Doku_Parser_Mode_file extends Doku_Parser_Mode { 571 572 function connectTo($mode) { 573 $this->Lexer->addEntryPattern('<file>(?=.*\x3C/file\x3E)',$mode,'file'); 574 } 575 576 function postConnect() { 577 $this->Lexer->addExitPattern('</file>','file'); 578 } 579 580 function getSort() { 581 return 210; 582 } 583} 584 585//------------------------------------------------------------------- 586class Doku_Parser_Mode_quote extends Doku_Parser_Mode { 587 588 function Doku_Parser_Mode_quote() { 589 global $PARSER_MODES; 590 591 $this->allowedModes = array_merge ( 592 $PARSER_MODES['formatting'], 593 $PARSER_MODES['substition'], 594 $PARSER_MODES['disabled'], 595 $PARSER_MODES['protected'] #XXX new 596 ); 597 #$this->allowedModes[] = 'footnote'; 598 #$this->allowedModes[] = 'preformatted'; 599 #$this->allowedModes[] = 'unformatted'; 600 } 601 602 function connectTo($mode) { 603 $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote'); 604 } 605 606 function postConnect() { 607 $this->Lexer->addPattern('\n>{1,}','quote'); 608 $this->Lexer->addExitPattern('\n','quote'); 609 } 610 611 function getSort() { 612 return 220; 613 } 614} 615 616//------------------------------------------------------------------- 617class Doku_Parser_Mode_acronym extends Doku_Parser_Mode { 618 // A list 619 var $acronyms = array(); 620 var $pattern = ''; 621 622 function Doku_Parser_Mode_acronym($acronyms) { 623 $this->acronyms = $acronyms; 624 } 625 626 function preConnect() { 627 $bound = '[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]'; 628 $acronyms = array_map('Doku_Lexer_Escape',$this->acronyms); 629 $this->pattern = '(?<=^|'.$bound.')(?:'.join('|',$acronyms).')(?='.$bound.')'; 630 } 631 632 function connectTo($mode) { 633 if ( strlen($this->pattern) > 0 ) { 634 $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym'); 635 } 636 } 637 638 function getSort() { 639 return 240; 640 } 641} 642 643//------------------------------------------------------------------- 644class Doku_Parser_Mode_smiley extends Doku_Parser_Mode { 645 // A list 646 var $smileys = array(); 647 var $pattern = ''; 648 649 function Doku_Parser_Mode_smiley($smileys) { 650 $this->smileys = $smileys; 651 } 652 653 function preConnect() { 654 $sep = ''; 655 foreach ( $this->smileys as $smiley ) { 656 $this->pattern .= $sep.Doku_Lexer_Escape($smiley); 657 $sep = '|'; 658 } 659 } 660 661 function connectTo($mode) { 662 if ( strlen($this->pattern) > 0 ) { 663 $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley'); 664 } 665 } 666 667 function getSort() { 668 return 230; 669 } 670} 671 672//------------------------------------------------------------------- 673class Doku_Parser_Mode_wordblock extends Doku_Parser_Mode { 674 // A list 675 var $badwords = array(); 676 var $pattern = ''; 677 678 function Doku_Parser_Mode_wordblock($badwords) { 679 $this->badwords = $badwords; 680 } 681 682 function preConnect() { 683 684 if ( count($this->badwords) == 0 ) { 685 return; 686 } 687 688 $sep = ''; 689 foreach ( $this->badwords as $badword ) { 690 $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)'; 691 $sep = '|'; 692 } 693 694 } 695 696 function connectTo($mode) { 697 if ( strlen($this->pattern) > 0 ) { 698 $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock'); 699 } 700 } 701 702 function getSort() { 703 return 250; 704 } 705} 706 707//------------------------------------------------------------------- 708/** 709* @TODO Quotes and 640x480 are not supported - just straight replacements here 710*/ 711class Doku_Parser_Mode_entity extends Doku_Parser_Mode { 712 // A list 713 var $entities = array(); 714 var $pattern = ''; 715 716 function Doku_Parser_Mode_entity($entities) { 717 $this->entities = $entities; 718 } 719 720 function preConnect() { 721 $sep = ''; 722 foreach ( $this->entities as $entity ) { 723 $this->pattern .= $sep.Doku_Lexer_Escape($entity); 724 $sep = '|'; 725 } 726 } 727 728 function connectTo($mode) { 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)\d+[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 761 $this->Lexer->addSpecialPattern( 762 '(?<=^|\s)\'(?=\S)',$mode,'singlequoteopening' 763 ); 764 $this->Lexer->addSpecialPattern( 765 '(?<=^|\S)\'',$mode,'singlequoteclosing' 766 ); 767 $this->Lexer->addSpecialPattern( 768 '(?<=^|\s)"(?=\S)',$mode,'doublequoteopening' 769 ); 770 $this->Lexer->addSpecialPattern( 771 '(?<=^|\S)"',$mode,'doublequoteclosing' 772 ); 773 774 } 775 776 function getSort() { 777 return 280; 778 } 779} 780 781//------------------------------------------------------------------- 782class Doku_Parser_Mode_camelcaselink extends Doku_Parser_Mode { 783 784 function connectTo($mode) { 785 $this->Lexer->addSpecialPattern( 786 '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' 787 ); 788 } 789 790 function getSort() { 791 return 290; 792 } 793} 794 795//------------------------------------------------------------------- 796class Doku_Parser_Mode_internallink extends Doku_Parser_Mode { 797 798 function connectTo($mode) { 799 // Word boundaries? 800 $this->Lexer->addSpecialPattern("\[\[.+?\]\]",$mode,'internallink'); 801 } 802 803 function getSort() { 804 return 300; 805 } 806} 807 808//------------------------------------------------------------------- 809class Doku_Parser_Mode_media extends Doku_Parser_Mode { 810 811 function connectTo($mode) { 812 // Word boundaries? 813 $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media'); 814 } 815 816 function getSort() { 817 return 320; 818 } 819} 820 821//------------------------------------------------------------------- 822class Doku_Parser_Mode_rss extends Doku_Parser_Mode { 823 824 function connectTo($mode) { 825 $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss'); 826 } 827 828 function getSort() { 829 return 310; 830 } 831} 832 833//------------------------------------------------------------------- 834class Doku_Parser_Mode_externallink extends Doku_Parser_Mode { 835 var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc','ldap'); 836 var $patterns = array(); 837 838 function preConnect() { 839 840 $ltrs = '\w'; 841 $gunk = '/\#~:.?+=&%@!\-'; 842 $punc = '.:?\-;,'; 843 $host = $ltrs.$punc; 844 $any = $ltrs.$gunk.$punc; 845 846 foreach ( $this->schemes as $scheme ) { 847 $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 848 } 849 850 $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 851 $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])'; 852 853 } 854 855 function connectTo($mode) { 856 foreach ( $this->patterns as $pattern ) { 857 $this->Lexer->addSpecialPattern($pattern,$mode,'externallink'); 858 } 859 } 860 861 function getSort() { 862 return 330; 863 } 864} 865 866//------------------------------------------------------------------- 867class Doku_Parser_Mode_filelink extends Doku_Parser_Mode { 868 869 var $pattern; 870 871 function preConnect() { 872 873 $ltrs = '\w'; 874 $gunk = '/\#~:.?+=&%@!\-'; 875 $punc = '.:?\-;,'; 876 $host = $ltrs.$punc; 877 $any = $ltrs.$gunk.$punc; 878 879 $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['. 880 $punc.']*[^'.$any.']'; 881 } 882 883 function connectTo($mode) { 884 $this->Lexer->addSpecialPattern( 885 $this->pattern,$mode,'filelink'); 886 } 887 888 function getSort() { 889 return 360; 890 } 891} 892 893//------------------------------------------------------------------- 894class Doku_Parser_Mode_windowssharelink extends Doku_Parser_Mode { 895 896 var $pattern; 897 898 function preConnect() { 899 $this->pattern = "\\\\\\\\\w+?(?:\\\\[\w$]+)+"; 900 } 901 902 function connectTo($mode) { 903 $this->Lexer->addSpecialPattern( 904 $this->pattern,$mode,'windowssharelink'); 905 } 906 907 function getSort() { 908 return 350; 909 } 910} 911 912//------------------------------------------------------------------- 913class Doku_Parser_Mode_emaillink extends Doku_Parser_Mode { 914 915 function connectTo($mode) { 916 $this->Lexer->addSpecialPattern("<[\w0-9\-_.]+?@[\w\-]+\.[\w\-\.]+\.*[\w]+>",$mode,'emaillink'); 917 } 918 919 function getSort() { 920 return 340; 921 } 922} 923 924 925//Setup VIM: ex: et ts=4 enc=utf-8 : 926