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