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