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