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