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