xref: /dokuwiki/inc/parser/parser.php (revision a6755281caf089bc0d12d715100b727bc97aa8da)
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    // Called before any calls to connectTo
145    function preConnect() {}
146
147    function connectTo($mode) {}
148
149    // Called after all calls to connectTo
150    function postConnect() {}
151
152    function accepts($mode) {
153        return in_array($mode, $this->allowedModes );
154    }
155
156}
157
158//-------------------------------------------------------------------
159class Doku_Parser_Mode_Base extends Doku_Parser_Mode {
160
161    function Doku_Parser_Mode_Base() {
162        global $PARSER_MODES;
163
164        $this->allowedModes = array_merge (
165                $PARSER_MODES['container'],
166                $PARSER_MODES['baseonly'],
167                $PARSER_MODES['paragraphs'],
168                $PARSER_MODES['formatting'],
169                $PARSER_MODES['substition'],
170                $PARSER_MODES['protected'],
171                $PARSER_MODES['disabled']
172            );
173    }
174}
175
176//-------------------------------------------------------------------
177class Doku_Parser_Mode_Footnote extends Doku_Parser_Mode {
178
179    function Doku_Parser_Mode_Footnote() {
180        global $PARSER_MODES;
181
182        $this->allowedModes = array_merge (
183                $PARSER_MODES['container'],
184                $PARSER_MODES['formatting'],
185                $PARSER_MODES['substition'],
186                $PARSER_MODES['protected'],
187                $PARSER_MODES['disabled']
188            );
189
190    }
191
192    function connectTo($mode) {
193        $this->Lexer->addEntryPattern(
194            '\x28\x28(?=.*\x29\x29)',$mode,'footnote'
195            );
196    }
197
198    function postConnect() {
199        $this->Lexer->addExitPattern(
200            '\x29\x29','footnote'
201            );
202
203    }
204
205}
206
207//-------------------------------------------------------------------
208class Doku_Parser_Mode_Header extends Doku_Parser_Mode {
209
210    function preConnect() {
211        //we're not picky about the closing ones, two are enough
212
213        // Header 1 is special case - match 6 or more
214        $this->Lexer->addSpecialPattern(
215                            '[ \t]*={6,}[^\n]+={2,}[ \t]*(?=\n)',
216                            'base',
217                            'header'
218                        );
219
220        // For the rest, match exactly
221        for ( $i = 5; $i > 1; $i--) {
222            $this->Lexer->addSpecialPattern(
223                                '[ \t]*={'.$i.'}[^\n]+={2,}[ \t]*(?=\n)',
224                                'base',
225                                'header'
226                            );
227        }
228    }
229
230}
231
232//-------------------------------------------------------------------
233class Doku_Parser_Mode_NoToc extends Doku_Parser_Mode {
234
235    function connectTo($mode) {
236        $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc');
237    }
238
239}
240
241//-------------------------------------------------------------------
242class Doku_Parser_Mode_NoCache extends Doku_Parser_Mode {
243
244    function connectTo($mode) {
245        $this->Lexer->addSpecialPattern('~~NOCACHE~~',$mode,'nocache');
246    }
247
248}
249
250//-------------------------------------------------------------------
251class Doku_Parser_Mode_Linebreak extends Doku_Parser_Mode {
252
253    function connectTo($mode) {
254        $this->Lexer->addSpecialPattern('\x5C{2}(?=\s)',$mode,'linebreak');
255    }
256}
257
258//-------------------------------------------------------------------
259class Doku_Parser_Mode_Eol extends Doku_Parser_Mode {
260
261    function connectTo($mode) {
262        $badModes = array('listblock','table');
263        if ( in_array($mode, $badModes) ) {
264            return;
265        }
266        $this->Lexer->addSpecialPattern('\n',$mode,'eol');
267    }
268}
269
270//-------------------------------------------------------------------
271class Doku_Parser_Mode_HR extends Doku_Parser_Mode {
272
273    function connectTo($mode) {
274        $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr');
275    }
276
277}
278
279//-------------------------------------------------------------------
280class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
281    var $type;
282
283    var $formatting = array (
284        'strong' => array (
285            'entry'=>'\*\*(?=.*\*\*)',
286            'exit'=>'\*\*',
287            ),
288
289        'emphasis'=> array (
290            'entry'=>'//(?=.*//)',
291            'exit'=>'//',
292            ),
293
294        'underline'=> array (
295            'entry'=>'__(?=.*__)',
296            'exit'=>'__',
297            ),
298
299        'monospace'=> array (
300            'entry'=>'\x27\x27(?=.*\x27\x27)',
301            'exit'=>'\x27\x27',
302            ),
303
304        'subscript'=> array (
305            'entry'=>'<sub>(?=.*\x3C/sub\x3E)',
306            'exit'=>'</sub>',
307            ),
308
309        'superscript'=> array (
310            'entry'=>'<sup>(?=.*\x3C/sup\x3E)',
311            'exit'=>'</sup>',
312            ),
313
314        'deleted'=> array (
315            'entry'=>'<del>(?=.*\x3C/del\x3E)',
316            'exit'=>'</del>',
317            ),
318        );
319
320    function Doku_Parser_Mode_Formatting($type) {
321        global $PARSER_MODES;
322
323        if ( !array_key_exists($type, $this->formatting) ) {
324            trigger_error('Invalid formatting type '.$type, E_USER_WARNING);
325        }
326
327        $this->type = $type;
328
329        // formatting may contain other formatting but not it self
330        $modes = $PARSER_MODES['formatting'];
331        $key = array_search($type, $modes);
332        if ( is_int($key) ) {
333            unset($modes[$key]);
334        }
335
336        $this->allowedModes = array_merge (
337                $modes,
338                $PARSER_MODES['substition'],
339                $PARSER_MODES['disabled']
340            );
341    }
342
343    function connectTo($mode) {
344
345        // Can't nest formatting in itself
346        if ( $mode == $this->type ) {
347            return;
348        }
349
350        $this->Lexer->addEntryPattern(
351                $this->formatting[$this->type]['entry'],
352                $mode,
353                $this->type
354            );
355    }
356
357    function postConnect() {
358
359        $this->Lexer->addExitPattern(
360            $this->formatting[$this->type]['exit'],
361            $this->type
362            );
363
364    }
365}
366
367//-------------------------------------------------------------------
368class Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode {
369
370    function Doku_Parser_Mode_ListBlock() {
371        global $PARSER_MODES;
372
373        $this->allowedModes = array_merge (
374                $PARSER_MODES['formatting'],
375                $PARSER_MODES['substition'],
376                $PARSER_MODES['disabled'],
377                $PARSER_MODES['protected'] #XXX new
378            );
379
380    //    $this->allowedModes[] = 'footnote';
381    }
382
383    function connectTo($mode) {
384        $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock');
385        $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock');
386
387        $this->Lexer->addPattern('\n {2,}[\-\*]','listblock');
388        $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock');
389
390    }
391
392    function postConnect() {
393        $this->Lexer->addExitPattern('\n','listblock');
394    }
395}
396
397//-------------------------------------------------------------------
398class Doku_Parser_Mode_Table extends Doku_Parser_Mode {
399
400    function Doku_Parser_Mode_Table() {
401        global $PARSER_MODES;
402
403        $this->allowedModes = array_merge (
404                $PARSER_MODES['formatting'],
405                $PARSER_MODES['substition'],
406                $PARSER_MODES['disabled'],
407                $PARSER_MODES['protected'] #XXX new
408            );
409        #$this->allowedModes[] = 'footnote';
410        #$this->allowedModes[] = 'preformatted';
411        #$this->allowedModes[] = 'unformatted';
412    }
413
414    function connectTo($mode) {
415        $this->Lexer->addEntryPattern('\n\^',$mode,'table');
416        $this->Lexer->addEntryPattern('\n\|',$mode,'table');
417    }
418
419    function postConnect() {
420        $this->Lexer->addPattern('\n\^','table');
421        $this->Lexer->addPattern('\n\|','table');
422        $this->Lexer->addPattern(' {2,}','table');
423        $this->Lexer->addPattern('\^','table');
424        $this->Lexer->addPattern('\|','table');
425        $this->Lexer->addExitPattern('\n','table');
426    }
427}
428
429//-------------------------------------------------------------------
430class Doku_Parser_Mode_Unformatted extends Doku_Parser_Mode {
431
432    function connectTo($mode) {
433        $this->Lexer->addEntryPattern('<nowiki>(?=.*\x3C/nowiki\x3E)',$mode,'unformatted');
434        $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt');
435    }
436
437    function postConnect() {
438        $this->Lexer->addExitPattern('</nowiki>','unformatted');
439        $this->Lexer->addExitPattern('%%','unformattedalt');
440        $this->Lexer->mapHandler('unformattedalt','unformatted');
441    }
442
443}
444
445//-------------------------------------------------------------------
446class Doku_Parser_Mode_PHP extends Doku_Parser_Mode {
447
448    function connectTo($mode) {
449        $this->Lexer->addEntryPattern('<php>(?=.*\x3C/php\x3E)',$mode,'php');
450    }
451
452    function postConnect() {
453        $this->Lexer->addExitPattern('</php>','php');
454    }
455
456}
457
458//-------------------------------------------------------------------
459class Doku_Parser_Mode_HTML extends Doku_Parser_Mode {
460
461    function connectTo($mode) {
462        $this->Lexer->addEntryPattern('<html>(?=.*\x3C/html\x3E)',$mode,'html');
463    }
464
465    function postConnect() {
466        $this->Lexer->addExitPattern('</html>','html');
467    }
468
469}
470
471//-------------------------------------------------------------------
472class Doku_Parser_Mode_Preformatted extends Doku_Parser_Mode {
473
474    function connectTo($mode) {
475        // Has hard coded awareness of lists...
476        $this->Lexer->addEntryPattern('\n  (?![\*\-])',$mode,'preformatted');
477        $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted');
478
479        // How to effect a sub pattern with the Lexer!
480        $this->Lexer->addPattern('\n  ','preformatted');
481        $this->Lexer->addPattern('\n\t','preformatted');
482
483    }
484
485    function postConnect() {
486        $this->Lexer->addExitPattern('\n','preformatted');
487    }
488
489}
490
491//-------------------------------------------------------------------
492class Doku_Parser_Mode_Code extends Doku_Parser_Mode {
493
494    function connectTo($mode) {
495        $this->Lexer->addEntryPattern('<code(?=.*\x3C/code\x3E)',$mode,'code');
496    }
497
498    function postConnect() {
499        $this->Lexer->addExitPattern('</code>','code');
500    }
501
502}
503
504//-------------------------------------------------------------------
505class Doku_Parser_Mode_File extends Doku_Parser_Mode {
506
507    function connectTo($mode) {
508        $this->Lexer->addEntryPattern('<file>(?=.*\x3C/file\x3E)',$mode,'file');
509    }
510
511    function postConnect() {
512        $this->Lexer->addExitPattern('</file>','file');
513    }
514
515}
516
517//-------------------------------------------------------------------
518class Doku_Parser_Mode_Quote extends Doku_Parser_Mode {
519
520    function Doku_Parser_Mode_Quote() {
521        global $PARSER_MODES;
522
523        $this->allowedModes = array_merge (
524                $PARSER_MODES['formatting'],
525                $PARSER_MODES['substition'],
526                $PARSER_MODES['disabled'],
527                $PARSER_MODES['protected'] #XXX new
528            );
529            #$this->allowedModes[] = 'footnote';
530            #$this->allowedModes[] = 'preformatted';
531            #$this->allowedModes[] = 'unformatted';
532    }
533
534    function connectTo($mode) {
535        $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote');
536    }
537
538    function postConnect() {
539        $this->Lexer->addPattern('\n>{1,}','quote');
540        $this->Lexer->addExitPattern('\n','quote');
541    }
542
543}
544
545//-------------------------------------------------------------------
546class Doku_Parser_Mode_Acronym extends Doku_Parser_Mode {
547    // A list
548    var $acronyms = array();
549    var $pattern = '';
550
551    function Doku_Parser_Mode_Acronym($acronyms) {
552        $this->acronyms = $acronyms;
553    }
554
555    function preConnect() {
556        $sep = '';
557        foreach ( $this->acronyms as $acronym ) {
558            $this->pattern .= $sep.'(?<=\b)'.Doku_Lexer_Escape($acronym).'(?=\b)';
559            $sep = '|';
560        }
561    }
562
563    function connectTo($mode) {
564        if ( strlen($this->pattern) > 0 ) {
565            $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym');
566        }
567    }
568
569}
570
571//-------------------------------------------------------------------
572class Doku_Parser_Mode_Smiley extends Doku_Parser_Mode {
573    // A list
574    var $smileys = array();
575    var $pattern = '';
576
577    function Doku_Parser_Mode_Smiley($smileys) {
578        $this->smileys = $smileys;
579    }
580
581    function preConnect() {
582        $sep = '';
583        foreach ( $this->smileys as $smiley ) {
584            $this->pattern .= $sep.Doku_Lexer_Escape($smiley);
585            $sep = '|';
586        }
587    }
588
589    function connectTo($mode) {
590        if ( strlen($this->pattern) > 0 ) {
591            $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley');
592        }
593    }
594
595}
596
597//-------------------------------------------------------------------
598class Doku_Parser_Mode_Wordblock extends Doku_Parser_Mode {
599    // A list
600    var $badwords = array();
601    var $pattern = '';
602
603    function Doku_Parser_Mode_Wordblock($badwords) {
604        $this->badwords = $badwords;
605    }
606
607    function preConnect() {
608
609        if ( count($this->badwords) == 0 ) {
610            return;
611        }
612
613        $sep = '';
614        foreach ( $this->badwords as $badword ) {
615            $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)';
616            $sep = '|';
617        }
618
619    }
620
621    function connectTo($mode) {
622        if ( strlen($this->pattern) > 0 ) {
623            $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock');
624        }
625    }
626
627}
628
629//-------------------------------------------------------------------
630/**
631* @TODO Quotes and 640x480 are not supported - just straight replacements here
632*/
633class Doku_Parser_Mode_Entity extends Doku_Parser_Mode {
634    // A list
635    var $entities = array();
636    var $pattern = '';
637
638    function Doku_Parser_Mode_Entity($entities) {
639        $this->entities = $entities;
640    }
641
642    function preConnect() {
643        $sep = '';
644        foreach ( $this->entities as $entity ) {
645            $this->pattern .= $sep.Doku_Lexer_Escape($entity);
646            $sep = '|';
647        }
648    }
649
650    function connectTo($mode) {
651        if ( strlen($this->pattern) > 0 ) {
652            $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity');
653        }
654    }
655
656}
657
658//-------------------------------------------------------------------
659// Implements the 640x480 replacement
660class Doku_Parser_Mode_MultiplyEntity extends Doku_Parser_Mode {
661
662    function connectTo($mode) {
663
664        $this->Lexer->addSpecialPattern(
665                    '(?<=\b)\d+[x|X]\d+(?=\b)',$mode,'multiplyentity'
666                );
667
668    }
669
670}
671
672//-------------------------------------------------------------------
673class Doku_Parser_Mode_Quotes extends Doku_Parser_Mode {
674
675    function connectTo($mode) {
676
677        $this->Lexer->addSpecialPattern(
678                    '(?<=\s)\'(?=\S)',$mode,'singlequoteopening'
679                );
680        $this->Lexer->addSpecialPattern(
681                    '(?<=^|\S)\'',$mode,'singlequoteclosing'
682                );
683        $this->Lexer->addSpecialPattern(
684                    '(?<=^|\s)"(?=\S)',$mode,'doublequoteopening'
685                );
686        $this->Lexer->addSpecialPattern(
687                    '(?<=\S)"',$mode,'doublequoteclosing'
688                );
689
690    }
691
692}
693
694//-------------------------------------------------------------------
695class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode {
696
697    function connectTo($mode) {
698        $this->Lexer->addSpecialPattern(
699                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink'
700            );
701    }
702
703}
704
705//-------------------------------------------------------------------
706class Doku_Parser_Mode_InternalLink extends Doku_Parser_Mode {
707
708    function connectTo($mode) {
709        // Word boundaries?
710        $this->Lexer->addSpecialPattern("\[\[.+?\]\]",$mode,'internallink');
711    }
712
713}
714
715//-------------------------------------------------------------------
716class Doku_Parser_Mode_Media extends Doku_Parser_Mode {
717
718    function connectTo($mode) {
719        // Word boundaries?
720        $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media');
721    }
722
723}
724
725//-------------------------------------------------------------------
726class Doku_Parser_Mode_RSS extends Doku_Parser_Mode {
727
728    function connectTo($mode) {
729        $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss');
730    }
731
732}
733
734//-------------------------------------------------------------------
735class Doku_Parser_Mode_ExternalLink extends Doku_Parser_Mode {
736    var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc');
737    var $patterns = array();
738
739    function preConnect() {
740
741        $ltrs = '\w';
742        $gunk = '/\#~:.?+=&%@!\-';
743        $punc = '.:?\-;,';
744        $host = $ltrs.$punc;
745        $any  = $ltrs.$gunk.$punc;
746
747        foreach ( $this->schemes as $scheme ) {
748            $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
749        }
750
751        $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
752        $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
753
754    }
755
756    function connectTo($mode) {
757        foreach ( $this->patterns as $pattern ) {
758            $this->Lexer->addSpecialPattern($pattern,$mode,'externallink');
759        }
760    }
761
762}
763
764//-------------------------------------------------------------------
765class Doku_Parser_Mode_FileLink extends Doku_Parser_Mode {
766
767    var $pattern;
768
769    function preConnect() {
770
771        $ltrs = '\w';
772        $gunk = '/\#~:.?+=&%@!\-';
773        $punc = '.:?\-;,';
774        $host = $ltrs.$punc;
775        $any  = $ltrs.$gunk.$punc;
776
777        $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['.
778            $punc.']*[^'.$any.']';
779    }
780
781    function connectTo($mode) {
782        $this->Lexer->addSpecialPattern(
783            $this->pattern,$mode,'filelink');
784    }
785
786
787}
788
789//-------------------------------------------------------------------
790class Doku_Parser_Mode_WindowsShareLink extends Doku_Parser_Mode {
791
792    var $pattern;
793
794    function preConnect() {
795
796        $ltrs = '\w';
797        $gunk = '/\#~:.?+=&%@!\-';
798        $punc = '.:?\-;,';
799        $host = $ltrs.$punc;
800        $any  = $ltrs.$gunk.$punc;
801
802        $this->pattern = "[$gunk$punc\s]\\\\\\\\[$host]+?\\\\[$any]+?(?=['.$punc.']*[^'.$any.'])";
803    }
804
805    function connectTo($mode) {
806        $this->Lexer->addSpecialPattern(
807            $this->pattern,$mode,'windowssharelink');
808    }
809
810
811}
812
813//-------------------------------------------------------------------
814class Doku_Parser_Mode_EmailLink extends Doku_Parser_Mode {
815
816    function connectTo($mode) {
817    //<([\w0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)>
818        $this->Lexer->addSpecialPattern("<[\w0-9\-_.]+?@[\w\-]+\.[\w\-\.]+\.*[\w]+>",$mode,'emaillink');
819    }
820
821}
822
823//-------------------------------------------------------------------
824//
825// XXX deprecated - replace by $PARSER_MODES
826//
827// Help fns to keep mode lists - used to make it easier to populate
828// the list of modes another mode accepts
829
830/*
831
832// Can contain many other modes
833// E.g. a footnote can containing formatting etc.
834function Doku_Parser_BlockContainers() {
835    $modes = array(
836        'footnote', 'listblock', 'table','quote',
837        // hr breaks the principle but HRs should not be used in tables / lists
838        // so put it here
839        'hr',
840    );
841    return $modes;
842}
843
844// Used to mark paragraph boundaries
845function Doku_Parser_Paragraphs() {
846    $modes = array(
847        'eol'
848    );
849    return $modes;
850}
851
852// Can only be used by the base mode
853function Doku_Parser_BaseOnly() {
854    $modes = array(
855        'header'
856    );
857    return $modes;
858}
859
860// "Styling" modes that format text.
861function Doku_Parser_Formatting($remove = '') {
862    $modes = array(
863        'strong', 'emphasis', 'underline', 'monospace',
864        'subscript', 'superscript', 'deleted',
865        );
866    $key = array_search($remove, $modes);
867    if ( is_int($key) ) {
868        unset($modes[$key]);
869    }
870
871    return $modes;
872}
873
874// Modes where the token is simply replaced - contain no
875// other modes
876function Doku_Parser_Substition() {
877    $modes = array(
878        'acronym','smiley','wordblock','entity','camelcaselink',
879        'internallink','media','externallink','linebreak','emaillink',
880        'windowssharelink','filelink','notoc','nocache','multiplyentity',
881        'quotes','rss',
882    );
883    return $modes;
884}
885
886// Modes which have a start and end token but inside which
887// no other modes should be applied
888function Doku_Parser_Protected() {
889    $modes = array(
890        'preformatted','code','file',
891        'php','html','quote',
892    );
893    return $modes;
894}
895
896// Disable wiki markup inside this mode
897function Doku_Parser_Disabled() {
898    $modes = array(
899        'unformatted'
900    );
901    return $modes;
902}
903*/
904
905// --------------------------------------------------------------------------
906
907//Setup VIM: ex: et ts=4 enc=utf-8 :
908