xref: /dokuwiki/inc/parser/parser.php (revision 5e100747059d6148199a91dfae13217e89dd4344)
1<?php
2
3if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
4
5require_once DOKU_INC . 'inc/parser/lexer.php';
6require_once DOKU_INC . 'inc/parser/handler.php';
7
8//-------------------------------------------------------------------
9
10/**
11* Sets up the Lexer with modes and points it to the Handler
12* For an intro to the Lexer see: wiki:parser
13*/
14class Doku_Parser {
15
16    var $Handler;
17
18    var $Lexer;
19
20    var $modes = array();
21
22    var $connected = FALSE;
23
24    function addBaseMode(& $BaseMode) {
25        $this->modes['base'] = & $BaseMode;
26        if ( !$this->Lexer ) {
27            $this->Lexer = & new Doku_Lexer($this->Handler,'base', TRUE);
28        }
29        $this->modes['base']->Lexer = & $this->Lexer;
30    }
31
32    /**
33    * PHP preserves order of associative elements
34    * Mode sequence is important
35    */
36    function addMode($name, & $Mode) {
37        if ( !isset($this->modes['base']) ) {
38            $this->addBaseMode(new Doku_Parser_Mode_Base());
39        }
40        $Mode->Lexer = & $this->Lexer;
41        $this->modes[$name] = & $Mode;
42    }
43
44    function connectModes() {
45
46        if ( $this->connected ) {
47            return;
48        }
49
50        foreach ( array_keys($this->modes) as $mode ) {
51
52            // Base isn't connected to anything
53            if ( $mode == 'base' ) {
54                continue;
55            }
56
57            $this->modes[$mode]->preConnect();
58
59            foreach ( array_keys($this->modes) as $cm ) {
60
61                if ( $this->modes[$cm]->accepts($mode) ) {
62                    $this->modes[$mode]->connectTo($cm);
63                }
64
65            }
66
67            $this->modes[$mode]->postConnect();
68        }
69
70        $this->connected = TRUE;
71    }
72
73    function parse($doc) {
74        if ( $this->Lexer ) {
75            $this->connectModes();
76            // Normalize CRs and pad doc
77            $doc = "\n".str_replace("\r\n","\n",$doc)."\n";
78            $this->Lexer->parse($doc);
79            $this->Handler->_finalize();
80            return $this->Handler->calls;
81        } else {
82            return FALSE;
83        }
84    }
85
86}
87
88//-------------------------------------------------------------------
89/**
90 * This class and all the subclasses below are
91 * used to reduce the effort required to register
92 * modes with the Lexer. For performance these
93 * could all be eliminated later perhaps, or
94 * the Parser could be serialized to a file once
95 * all modes are registered
96 *
97 * @author Harry Fuecks <harryf@gmail.com>
98*/
99class Doku_Parser_Mode {
100
101    var $Lexer;
102
103    var $allowedModes = array();
104
105    // Called before any calls to connectTo
106    function preConnect() {}
107
108    function connectTo($mode) {}
109
110    // Called after all calls to connectTo
111    function postConnect() {}
112
113    function accepts($mode) {
114        return in_array($mode, $this->allowedModes );
115    }
116
117}
118
119//-------------------------------------------------------------------
120class Doku_Parser_Mode_Base extends Doku_Parser_Mode {
121
122    function Doku_Parser_Mode_Base() {
123
124        $this->allowedModes = array_merge (
125                Doku_Parser_BlockContainers(),
126                Doku_Parser_BaseOnly(),
127                Doku_Parser_Paragraphs(),
128                Doku_Parser_Formatting(),
129                Doku_Parser_Substition(),
130                Doku_Parser_Protected(),
131                Doku_Parser_Disabled()
132            );
133    }
134}
135
136//-------------------------------------------------------------------
137class Doku_Parser_Mode_Footnote extends Doku_Parser_Mode {
138
139    function Doku_Parser_Mode_Footnote() {
140
141        $this->allowedModes = array_merge (
142                Doku_Parser_BlockContainers(),
143                Doku_Parser_Formatting(),
144                Doku_Parser_Substition(),
145                Doku_Parser_Protected(),
146                Doku_Parser_Disabled()
147            );
148
149    }
150
151    function connectTo($mode) {
152        $this->Lexer->addEntryPattern(
153            '\x28\x28(?=.*\x29\x29)',$mode,'footnote'
154            );
155    }
156
157    function postConnect() {
158        $this->Lexer->addExitPattern(
159            '\x29\x29','footnote'
160            );
161
162    }
163
164}
165
166//-------------------------------------------------------------------
167class Doku_Parser_Mode_Header extends Doku_Parser_Mode {
168
169    function preConnect() {
170        //we're not picky about the closing ones, two are enough
171
172        // Header 1 is special case - match 6 or more
173        $this->Lexer->addSpecialPattern(
174                            '[ \t]*={6,}[^\n]+={2,}[ \t]*(?=\n)',
175                            'base',
176                            'header'
177                        );
178
179        // For the rest, match exactly
180        for ( $i = 5; $i > 1; $i--) {
181            $this->Lexer->addSpecialPattern(
182                                '[ \t]*={'.$i.'}[^\n]+={2,}[ \t]*(?=\n)',
183                                'base',
184                                'header'
185                            );
186        }
187    }
188
189}
190
191//-------------------------------------------------------------------
192class Doku_Parser_Mode_NoToc extends Doku_Parser_Mode {
193
194    function connectTo($mode) {
195        $this->Lexer->addSpecialPattern('~~NOTOC~~',$mode,'notoc');
196    }
197
198}
199
200//-------------------------------------------------------------------
201class Doku_Parser_Mode_Linebreak extends Doku_Parser_Mode {
202
203    function connectTo($mode) {
204        $this->Lexer->addSpecialPattern('\x5C{2}(?=\s)',$mode,'linebreak');
205    }
206}
207
208//-------------------------------------------------------------------
209class Doku_Parser_Mode_Eol extends Doku_Parser_Mode {
210
211    function connectTo($mode) {
212        $badModes = array('listblock','table');
213        if ( in_array($mode, $badModes) ) {
214            return;
215        }
216        $this->Lexer->addSpecialPattern('\n',$mode,'eol');
217    }
218}
219
220//-------------------------------------------------------------------
221class Doku_Parser_Mode_HR extends Doku_Parser_Mode {
222
223    function connectTo($mode) {
224        $this->Lexer->addSpecialPattern('\n[ \t]*-{4,}[ \t]*(?=\n)',$mode,'hr');
225    }
226
227}
228
229//-------------------------------------------------------------------
230class Doku_Parser_Mode_Formatting extends Doku_Parser_Mode {
231
232    var $type;
233
234    var $formatting = array (
235        'strong' => array (
236            'entry'=>'\*\*(?=.*\*\*)',
237            'exit'=>'\*\*',
238            ),
239
240        'emphasis'=> array (
241            'entry'=>'//(?=.*//)',
242            'exit'=>'//',
243            ),
244
245        'underline'=> array (
246            'entry'=>'__(?=.*__)',
247            'exit'=>'__',
248            ),
249
250        'monospace'=> array (
251            'entry'=>'\x27\x27(?=.*\x27\x27)',
252            'exit'=>'\x27\x27',
253            ),
254
255        'subscript'=> array (
256            'entry'=>'<sub>(?=.*\x3C/sub\x3E)',
257            'exit'=>'</sub>',
258            ),
259
260        'superscript'=> array (
261            'entry'=>'<sup>(?=.*\x3C/sup\x3E)',
262            'exit'=>'</sup>',
263            ),
264
265        'deleted'=> array (
266            'entry'=>'<del>(?=.*\x3C/del\x3E)',
267            'exit'=>'</del>',
268            ),
269        );
270
271    function Doku_Parser_Mode_Formatting($type) {
272
273        if ( !array_key_exists($type, $this->formatting) ) {
274            trigger_error('Invalid formatting type '.$type, E_USER_WARNING);
275        }
276
277        $this->type = $type;
278
279        $this->allowedModes = array_merge (
280                Doku_Parser_Formatting($type),
281                Doku_Parser_Substition(),
282                Doku_Parser_Disabled()
283            );
284
285    }
286
287    function connectTo($mode) {
288
289        // Can't nest formatting in itself
290        if ( $mode == $this->type ) {
291            return;
292        }
293
294        $this->Lexer->addEntryPattern(
295                $this->formatting[$this->type]['entry'],
296                $mode,
297                $this->type
298            );
299    }
300
301    function postConnect() {
302
303        $this->Lexer->addExitPattern(
304            $this->formatting[$this->type]['exit'],
305            $this->type
306            );
307
308    }
309}
310
311//-------------------------------------------------------------------
312class Doku_Parser_Mode_ListBlock extends Doku_Parser_Mode {
313
314    function Doku_Parser_Mode_ListBlock() {
315
316        $this->allowedModes = array_merge (
317                Doku_Parser_Formatting(),
318                Doku_Parser_Substition(),
319                Doku_Parser_Disabled()
320            );
321
322        $this->allowedModes[] = 'footnote';
323        $this->allowedModes[] = 'preformatted';
324        $this->allowedModes[] = 'unformatted';
325        $this->allowedModes[] = 'html';
326        $this->allowedModes[] = 'php';
327        $this->allowedModes[] = 'code';
328        $this->allowedModes[] = 'file';
329    }
330
331    function connectTo($mode) {
332        $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock');
333        $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock');
334
335        $this->Lexer->addPattern('\n {2,}[\-\*]','listblock');
336        $this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock');
337
338    }
339
340    function postConnect() {
341        $this->Lexer->addExitPattern('\n','listblock');
342    }
343}
344
345//-------------------------------------------------------------------
346class Doku_Parser_Mode_Table extends Doku_Parser_Mode {
347
348    function Doku_Parser_Mode_Table() {
349
350        $this->allowedModes = array_merge (
351                Doku_Parser_Formatting(),
352                Doku_Parser_Substition(),
353                Doku_Parser_Disabled()
354            );
355        $this->allowedModes[] = 'footnote';
356        $this->allowedModes[] = 'preformatted';
357        $this->allowedModes[] = 'unformatted';
358    }
359
360    function connectTo($mode) {
361        $this->Lexer->addEntryPattern('\n\^',$mode,'table');
362        $this->Lexer->addEntryPattern('\n\|',$mode,'table');
363    }
364
365    function postConnect() {
366        $this->Lexer->addPattern('\n\^','table');
367        $this->Lexer->addPattern('\n\|','table');
368        $this->Lexer->addPattern(' {2,}','table');
369        $this->Lexer->addPattern('\^','table');
370        $this->Lexer->addPattern('\|','table');
371        $this->Lexer->addExitPattern('\n','table');
372    }
373}
374
375//-------------------------------------------------------------------
376class Doku_Parser_Mode_Unformatted extends Doku_Parser_Mode {
377
378    function connectTo($mode) {
379        $this->Lexer->addEntryPattern('<nowiki>(?=.*\x3C/nowiki\x3E)',$mode,'unformatted');
380        $this->Lexer->addEntryPattern('%%(?=.*%%)',$mode,'unformattedalt');
381    }
382
383    function postConnect() {
384        $this->Lexer->addExitPattern('</nowiki>','unformatted');
385        $this->Lexer->addExitPattern('%%','unformattedalt');
386        $this->Lexer->mapHandler('unformattedalt','unformatted');
387    }
388
389}
390
391//-------------------------------------------------------------------
392class Doku_Parser_Mode_PHP extends Doku_Parser_Mode {
393
394    function connectTo($mode) {
395        $this->Lexer->addEntryPattern('<php>(?=.*\x3C/php\x3E)',$mode,'php');
396    }
397
398    function postConnect() {
399        $this->Lexer->addExitPattern('</php>','php');
400    }
401
402}
403
404//-------------------------------------------------------------------
405class Doku_Parser_Mode_HTML extends Doku_Parser_Mode {
406
407    function connectTo($mode) {
408        $this->Lexer->addEntryPattern('<html>(?=.*\x3C/html\x3E)',$mode,'html');
409    }
410
411    function postConnect() {
412        $this->Lexer->addExitPattern('</html>','html');
413    }
414
415}
416
417//-------------------------------------------------------------------
418class Doku_Parser_Mode_Preformatted extends Doku_Parser_Mode {
419
420    function connectTo($mode) {
421        // Has hard coded awareness of lists...
422        $this->Lexer->addEntryPattern('\n  (?![\*\-])',$mode,'preformatted');
423        $this->Lexer->addEntryPattern('\n\t(?![\*\-])',$mode,'preformatted');
424
425        // How to effect a sub pattern with the Lexer!
426        $this->Lexer->addPattern('\n  ','preformatted');
427        $this->Lexer->addPattern('\n\t','preformatted');
428
429    }
430
431    function postConnect() {
432        $this->Lexer->addExitPattern('\n','preformatted');
433    }
434
435}
436
437//-------------------------------------------------------------------
438class Doku_Parser_Mode_Code extends Doku_Parser_Mode {
439
440    function connectTo($mode) {
441        $this->Lexer->addEntryPattern('<code(?=.*\x3C/code\x3E)',$mode,'code');
442    }
443
444    function postConnect() {
445        $this->Lexer->addExitPattern('</code>','code');
446    }
447
448}
449
450//-------------------------------------------------------------------
451class Doku_Parser_Mode_File extends Doku_Parser_Mode {
452
453    function connectTo($mode) {
454        $this->Lexer->addEntryPattern('<file>(?=.*\x3C/file\x3E)',$mode,'file');
455    }
456
457    function postConnect() {
458        $this->Lexer->addExitPattern('</file>','file');
459    }
460
461}
462
463//-------------------------------------------------------------------
464class Doku_Parser_Mode_Quote extends Doku_Parser_Mode {
465
466    function Doku_Parser_Mode_Quote() {
467
468        $this->allowedModes = array_merge (
469                Doku_Parser_Formatting(),
470                Doku_Parser_Substition(),
471                Doku_Parser_Disabled()
472            );
473            $this->allowedModes[] = 'footnote';
474            $this->allowedModes[] = 'preformatted';
475            $this->allowedModes[] = 'unformatted';
476    }
477
478    function connectTo($mode) {
479        $this->Lexer->addEntryPattern('\n>{1,}',$mode,'quote');
480    }
481
482    function postConnect() {
483        $this->Lexer->addPattern('\n>{1,}','quote');
484        $this->Lexer->addExitPattern('\n','quote');
485    }
486
487}
488
489//-------------------------------------------------------------------
490class Doku_Parser_Mode_Acronym extends Doku_Parser_Mode {
491    // A list
492    var $acronyms = array();
493    var $pattern = '';
494
495    function Doku_Parser_Mode_Acronym($acronyms) {
496        $this->acronyms = $acronyms;
497    }
498
499    function preConnect() {
500        $sep = '';
501        foreach ( $this->acronyms as $acronym ) {
502            $this->pattern .= $sep.'(?<=\b)'.Doku_Lexer_Escape($acronym).'(?=\b)';
503            $sep = '|';
504        }
505    }
506
507    function connectTo($mode) {
508        if ( strlen($this->pattern) > 0 ) {
509            $this->Lexer->addSpecialPattern($this->pattern,$mode,'acronym');
510        }
511    }
512
513}
514
515//-------------------------------------------------------------------
516class Doku_Parser_Mode_Smiley extends Doku_Parser_Mode {
517    // A list
518    var $smileys = array();
519    var $pattern = '';
520
521    function Doku_Parser_Mode_Smiley($smileys) {
522        $this->smileys = $smileys;
523    }
524
525    function preConnect() {
526        $sep = '';
527        foreach ( $this->smileys as $smiley ) {
528            $this->pattern .= $sep.Doku_Lexer_Escape($smiley);
529            $sep = '|';
530        }
531    }
532
533    function connectTo($mode) {
534        if ( strlen($this->pattern) > 0 ) {
535            $this->Lexer->addSpecialPattern($this->pattern,$mode,'smiley');
536        }
537    }
538
539}
540
541//-------------------------------------------------------------------
542class Doku_Parser_Mode_Wordblock extends Doku_Parser_Mode {
543    // A list
544    var $badwords = array();
545    var $pattern = '';
546
547    function Doku_Parser_Mode_Wordblock($badwords) {
548        $this->badwords = $badwords;
549    }
550
551    function preConnect() {
552
553        if ( count($this->badwords) == 0 ) {
554            return;
555        }
556
557        $sep = '';
558        foreach ( $this->badwords as $badword ) {
559            $this->pattern .= $sep.'(?<=\b)(?i)'.Doku_Lexer_Escape($badword).'(?-i)(?=\b)';
560            $sep = '|';
561        }
562
563    }
564
565    function connectTo($mode) {
566        if ( strlen($this->pattern) > 0 ) {
567            $this->Lexer->addSpecialPattern($this->pattern,$mode,'wordblock');
568        }
569    }
570
571}
572
573//-------------------------------------------------------------------
574/**
575* @TODO Quotes and 640x480 are not supported - just straight replacements here
576*/
577class Doku_Parser_Mode_Entity extends Doku_Parser_Mode {
578    // A list
579    var $entities = array();
580    var $pattern = '';
581
582    function Doku_Parser_Mode_Entity($entities) {
583        $this->entities = $entities;
584    }
585
586    function preConnect() {
587        $sep = '';
588        foreach ( $this->entities as $entity ) {
589            $this->pattern .= $sep.Doku_Lexer_Escape($entity);
590            $sep = '|';
591        }
592    }
593
594    function connectTo($mode) {
595        if ( strlen($this->pattern) > 0 ) {
596            $this->Lexer->addSpecialPattern($this->pattern,$mode,'entity');
597        }
598    }
599
600}
601
602//-------------------------------------------------------------------
603// Implements the 640x480 replacement
604class Doku_Parser_Mode_MultiplyEntity extends Doku_Parser_Mode {
605
606    function connectTo($mode) {
607
608        $this->Lexer->addSpecialPattern(
609                    '(?<=\b)\d+[x|X]\d+(?=\b)',$mode,'multiplyentity'
610                );
611
612    }
613
614}
615
616//-------------------------------------------------------------------
617class Doku_Parser_Mode_Quotes extends Doku_Parser_Mode {
618
619    function connectTo($mode) {
620
621        $this->Lexer->addSpecialPattern(
622                    '(?<=\s)\'(?=\S)',$mode,'singlequoteopening'
623                );
624        $this->Lexer->addSpecialPattern(
625                    '(?<=^|\S)\'',$mode,'singlequoteclosing'
626                );
627        $this->Lexer->addSpecialPattern(
628                    '(?<=^|\s)"(?=\S)',$mode,'doublequoteopening'
629                );
630        $this->Lexer->addSpecialPattern(
631                    '(?<=\S)"',$mode,'doublequoteclosing'
632                );
633
634    }
635
636}
637
638//-------------------------------------------------------------------
639class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode {
640
641    function connectTo($mode) {
642        $this->Lexer->addSpecialPattern(
643                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink'
644            );
645    }
646
647}
648
649//-------------------------------------------------------------------
650class Doku_Parser_Mode_InternalLink extends Doku_Parser_Mode {
651
652    function connectTo($mode) {
653        // Word boundaries?
654        $this->Lexer->addSpecialPattern("\[\[[^\]]+?\]\]",$mode,'internallink');
655    }
656
657}
658
659//-------------------------------------------------------------------
660class Doku_Parser_Mode_Media extends Doku_Parser_Mode {
661
662    function connectTo($mode) {
663        // Word boundaries?
664        $this->Lexer->addSpecialPattern("\{\{[^\}]+\}\}",$mode,'media');
665    }
666
667}
668
669//-------------------------------------------------------------------
670class Doku_Parser_Mode_RSS extends Doku_Parser_Mode {
671
672    function connectTo($mode) {
673        $this->Lexer->addSpecialPattern("\{\{rss>[^\}]+\}\}",$mode,'rss');
674    }
675
676}
677
678//-------------------------------------------------------------------
679class Doku_Parser_Mode_ExternalLink extends Doku_Parser_Mode {
680    var $schemes = array('http','https','telnet','gopher','wais','ftp','ed2k','irc');
681    var $patterns = array();
682
683    function preConnect() {
684
685        $ltrs = '\w';
686        $gunk = '/\#~:.?+=&%@!\-';
687        $punc = '.:?\-;,';
688        $host = $ltrs.$punc;
689        $any  = $ltrs.$gunk.$punc;
690
691        foreach ( $this->schemes as $scheme ) {
692            $this->patterns[] = '\b(?i)'.$scheme.'(?-i)://['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
693        }
694
695        $this->patterns[] = '\b(?i)www?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
696        $this->patterns[] = '\b(?i)ftp?(?-i)\.['.$host.']+?\.['.$host.']+?['.$any.']+?(?=['.$punc.']*[^'.$any.'])';
697
698    }
699
700    function connectTo($mode) {
701        foreach ( $this->patterns as $pattern ) {
702            $this->Lexer->addSpecialPattern($pattern,$mode,'externallink');
703        }
704    }
705
706}
707
708//-------------------------------------------------------------------
709class Doku_Parser_Mode_FileLink extends Doku_Parser_Mode {
710
711    var $pattern;
712
713    function preConnect() {
714
715        $ltrs = '\w';
716        $gunk = '/\#~:.?+=&%@!\-';
717        $punc = '.:?\-;,';
718        $host = $ltrs.$punc;
719        $any  = $ltrs.$gunk.$punc;
720
721        $this->pattern = '\b(?i)file(?-i)://['.$any.']+?['.
722            $punc.']*[^'.$any.']';
723    }
724
725    function connectTo($mode) {
726        $this->Lexer->addSpecialPattern(
727            $this->pattern,$mode,'filelink');
728    }
729
730
731}
732
733//-------------------------------------------------------------------
734class Doku_Parser_Mode_WindowsShareLink extends Doku_Parser_Mode {
735
736    var $pattern;
737
738    function preConnect() {
739
740        $ltrs = '\w';
741        $gunk = '/\#~:.?+=&%@!\-';
742        $punc = '.:?\-;,';
743        $host = $ltrs.$punc;
744        $any  = $ltrs.$gunk.$punc;
745
746        $this->pattern = "[$gunk$punc\s]\\\\\\\\[$host]+?\\\\[$any]+?[$punc]*[^$any]";
747    }
748
749    function connectTo($mode) {
750        $this->Lexer->addSpecialPattern(
751            $this->pattern,$mode,'windowssharelink');
752    }
753
754
755}
756
757//-------------------------------------------------------------------
758class Doku_Parser_Mode_EmailLink extends Doku_Parser_Mode {
759
760    function connectTo($mode) {
761    //<([\w0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)>
762        $this->Lexer->addSpecialPattern("<[\w0-9\-_.]+?@[\w\-]+\.[\w\-\.]+\.*[\w]+>",$mode,'emaillink');
763    }
764
765}
766
767//-------------------------------------------------------------------
768// Help fns to keep mode lists - used to make it easier to populate
769// the list of modes another mode accepts
770
771// Can contain many other modes
772// E.g. a footnote can containing formatting etc.
773function Doku_Parser_BlockContainers() {
774    $modes = array(
775        'footnote', 'listblock', 'table','quote',
776        // hr breaks the principle but HRs should not be used in tables / lists
777        // so put it here
778        'hr',
779    );
780    return $modes;
781}
782
783// Used to mark paragraph boundaries
784function Doku_Parser_Paragraphs() {
785    $modes = array(
786        'eol'
787    );
788    return $modes;
789}
790
791// Can only be used by the base mode
792function Doku_Parser_BaseOnly() {
793    $modes = array(
794        'header'
795    );
796    return $modes;
797}
798
799// "Styling" modes that format text.
800function Doku_Parser_Formatting($remove = '') {
801    $modes = array(
802        'strong', 'emphasis', 'underline', 'monospace',
803        'subscript', 'superscript', 'deleted',
804        );
805    $key = array_search($remove, $modes);
806    if ( is_int($key) ) {
807        unset($modes[$key]);
808    }
809
810    return $modes;
811}
812
813// Modes where the token is simply replaced - contain no
814// other modes
815function Doku_Parser_Substition() {
816    $modes = array(
817        'acronym','smiley','wordblock','entity','camelcaselink',
818        'internallink','media','externallink','linebreak','emaillink',
819        'windowssharelink','filelink','notoc','multiplyentity',
820        'quotes','rss',
821    );
822    return $modes;
823}
824
825// Modes which have a start and end token but inside which
826// no other modes should be applied
827function Doku_Parser_Protected() {
828    $modes = array(
829        'preformatted','code','file',
830        'php','html','quote',
831    );
832    return $modes;
833}
834
835// Disable wiki markup inside this mode
836function Doku_Parser_Disabled() {
837    $modes = array(
838        'unformatted'
839    );
840    return $modes;
841}
842
843
844//Setup VIM: ex: et ts=4 enc=utf-8 :
845