xref: /dokuwiki/inc/parser/handler.php (revision 836f6efbf31a2a263102aea61ef0cc5d577aa9bb)
1<?php
2
3use dokuwiki\Handler\Block;
4use dokuwiki\Handler\CallWriter;
5use dokuwiki\Handler\Lists;
6use dokuwiki\Handler\Nest;
7use dokuwiki\Handler\Preformatted;
8use dokuwiki\Handler\Quote;
9use dokuwiki\Handler\Table;
10
11if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL', "\n");   // add this to make handling test cases simpler
12
13class Doku_Handler {
14
15    var $Renderer = null;
16
17    var $CallWriter = null;
18
19    var $calls = array();
20
21    var $status = array(
22        'section' => false,
23        'doublequote' => 0,
24    );
25
26    var $rewriteBlocks = true;
27
28    function __construct() {
29        $this->CallWriter = new CallWriter($this);
30    }
31
32    /**
33     * @param string $handler
34     * @param mixed $args
35     * @param integer|string $pos
36     */
37    function _addCall($handler, $args, $pos) {
38        $call = array($handler,$args, $pos);
39        $this->CallWriter->writeCall($call);
40    }
41
42    function addPluginCall($plugin, $args, $state, $pos, $match) {
43        $call = array('plugin',array($plugin, $args, $state, $match), $pos);
44        $this->CallWriter->writeCall($call);
45    }
46
47    function _finalize(){
48
49        $this->CallWriter->finalise();
50
51        if ( $this->status['section'] ) {
52            $last_call = end($this->calls);
53            array_push($this->calls,array('section_close',array(), $last_call[2]));
54        }
55
56        if ( $this->rewriteBlocks ) {
57            $B = new Block();
58            $this->calls = $B->process($this->calls);
59        }
60
61        trigger_event('PARSER_HANDLER_DONE',$this);
62
63        array_unshift($this->calls,array('document_start',array(),0));
64        $last_call = end($this->calls);
65        array_push($this->calls,array('document_end',array(),$last_call[2]));
66    }
67
68    /**
69     * fetch the current call and advance the pointer to the next one
70     *
71     * @return bool|mixed
72     */
73    function fetch() {
74        $call = current($this->calls);
75        if($call !== false) {
76            next($this->calls); //advance the pointer
77            return $call;
78        }
79        return false;
80    }
81
82
83    /**
84     * Special plugin handler
85     *
86     * This handler is called for all modes starting with 'plugin_'.
87     * An additional parameter with the plugin name is passed
88     *
89     * @author Andreas Gohr <andi@splitbrain.org>
90     *
91     * @param string|integer $match
92     * @param string|integer $state
93     * @param integer $pos
94     * @param $pluginname
95     *
96     * @return bool
97     */
98    function plugin($match, $state, $pos, $pluginname){
99        $data = array($match);
100        /** @var DokuWiki_Syntax_Plugin $plugin */
101        $plugin = plugin_load('syntax',$pluginname);
102        if($plugin != null){
103            $data = $plugin->handle($match, $state, $pos, $this);
104        }
105        if ($data !== false) {
106            $this->addPluginCall($pluginname,$data,$state,$pos,$match);
107        }
108        return true;
109    }
110
111    function base($match, $state, $pos) {
112        switch ( $state ) {
113            case DOKU_LEXER_UNMATCHED:
114                $this->_addCall('cdata',array($match), $pos);
115                return true;
116            break;
117        }
118    }
119
120    function header($match, $state, $pos) {
121        // get level and title
122        $title = trim($match);
123        $level = 7 - strspn($title,'=');
124        if($level < 1) $level = 1;
125        $title = trim($title,'=');
126        $title = trim($title);
127
128        if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
129
130        $this->_addCall('header',array($title,$level,$pos), $pos);
131
132        $this->_addCall('section_open',array($level),$pos);
133        $this->status['section'] = true;
134        return true;
135    }
136
137    function notoc($match, $state, $pos) {
138        $this->_addCall('notoc',array(),$pos);
139        return true;
140    }
141
142    function nocache($match, $state, $pos) {
143        $this->_addCall('nocache',array(),$pos);
144        return true;
145    }
146
147    function linebreak($match, $state, $pos) {
148        $this->_addCall('linebreak',array(),$pos);
149        return true;
150    }
151
152    function eol($match, $state, $pos) {
153        $this->_addCall('eol',array(),$pos);
154        return true;
155    }
156
157    function hr($match, $state, $pos) {
158        $this->_addCall('hr',array(),$pos);
159        return true;
160    }
161
162    /**
163     * @param string|integer $match
164     * @param string|integer $state
165     * @param integer $pos
166     * @param string $name
167     */
168    function _nestingTag($match, $state, $pos, $name) {
169        switch ( $state ) {
170            case DOKU_LEXER_ENTER:
171                $this->_addCall($name.'_open', array(), $pos);
172            break;
173            case DOKU_LEXER_EXIT:
174                $this->_addCall($name.'_close', array(), $pos);
175            break;
176            case DOKU_LEXER_UNMATCHED:
177                $this->_addCall('cdata',array($match), $pos);
178            break;
179        }
180    }
181
182    function strong($match, $state, $pos) {
183        $this->_nestingTag($match, $state, $pos, 'strong');
184        return true;
185    }
186
187    function emphasis($match, $state, $pos) {
188        $this->_nestingTag($match, $state, $pos, 'emphasis');
189        return true;
190    }
191
192    function underline($match, $state, $pos) {
193        $this->_nestingTag($match, $state, $pos, 'underline');
194        return true;
195    }
196
197    function monospace($match, $state, $pos) {
198        $this->_nestingTag($match, $state, $pos, 'monospace');
199        return true;
200    }
201
202    function subscript($match, $state, $pos) {
203        $this->_nestingTag($match, $state, $pos, 'subscript');
204        return true;
205    }
206
207    function superscript($match, $state, $pos) {
208        $this->_nestingTag($match, $state, $pos, 'superscript');
209        return true;
210    }
211
212    function deleted($match, $state, $pos) {
213        $this->_nestingTag($match, $state, $pos, 'deleted');
214        return true;
215    }
216
217
218    function footnote($match, $state, $pos) {
219        if (!isset($this->_footnote)) $this->_footnote = false;
220
221        switch ( $state ) {
222            case DOKU_LEXER_ENTER:
223                // footnotes can not be nested - however due to limitations in lexer it can't be prevented
224                // we will still enter a new footnote mode, we just do nothing
225                if ($this->_footnote) {
226                    $this->_addCall('cdata',array($match), $pos);
227                    break;
228                }
229                $this->_footnote = true;
230
231                $this->CallWriter = new Nest($this->CallWriter,'footnote_close');
232                $this->_addCall('footnote_open', array(), $pos);
233            break;
234            case DOKU_LEXER_EXIT:
235                // check whether we have already exitted the footnote mode, can happen if the modes were nested
236                if (!$this->_footnote) {
237                    $this->_addCall('cdata',array($match), $pos);
238                    break;
239                }
240
241                $this->_footnote = false;
242                $this->_addCall('footnote_close', array(), $pos);
243
244                /** @var Nest $reWriter */
245                $reWriter = $this->CallWriter;
246                $this->CallWriter = $reWriter->process();
247            break;
248            case DOKU_LEXER_UNMATCHED:
249                $this->_addCall('cdata', array($match), $pos);
250            break;
251        }
252        return true;
253    }
254
255    function listblock($match, $state, $pos) {
256        switch ( $state ) {
257            case DOKU_LEXER_ENTER:
258                $this->CallWriter = new Lists($this->CallWriter);
259                $this->_addCall('list_open', array($match), $pos);
260            break;
261            case DOKU_LEXER_EXIT:
262                $this->_addCall('list_close', array(), $pos);
263                /** @var Lists $reWriter */
264                $reWriter = $this->CallWriter;
265                $this->CallWriter = $reWriter->process();
266            break;
267            case DOKU_LEXER_MATCHED:
268                $this->_addCall('list_item', array($match), $pos);
269            break;
270            case DOKU_LEXER_UNMATCHED:
271                $this->_addCall('cdata', array($match), $pos);
272            break;
273        }
274        return true;
275    }
276
277    function unformatted($match, $state, $pos) {
278        if ( $state == DOKU_LEXER_UNMATCHED ) {
279            $this->_addCall('unformatted',array($match), $pos);
280        }
281        return true;
282    }
283
284    function php($match, $state, $pos) {
285        global $conf;
286        if ( $state == DOKU_LEXER_UNMATCHED ) {
287            $this->_addCall('php',array($match), $pos);
288        }
289        return true;
290    }
291
292    function phpblock($match, $state, $pos) {
293        global $conf;
294        if ( $state == DOKU_LEXER_UNMATCHED ) {
295            $this->_addCall('phpblock',array($match), $pos);
296        }
297        return true;
298    }
299
300    function html($match, $state, $pos) {
301        global $conf;
302        if ( $state == DOKU_LEXER_UNMATCHED ) {
303            $this->_addCall('html',array($match), $pos);
304        }
305        return true;
306    }
307
308    function htmlblock($match, $state, $pos) {
309        global $conf;
310        if ( $state == DOKU_LEXER_UNMATCHED ) {
311            $this->_addCall('htmlblock',array($match), $pos);
312        }
313        return true;
314    }
315
316    function preformatted($match, $state, $pos) {
317        switch ( $state ) {
318            case DOKU_LEXER_ENTER:
319                $this->CallWriter = new Preformatted($this->CallWriter);
320                $this->_addCall('preformatted_start',array(), $pos);
321            break;
322            case DOKU_LEXER_EXIT:
323                $this->_addCall('preformatted_end',array(), $pos);
324                /** @var Preformatted $reWriter */
325                $reWriter = $this->CallWriter;
326                $this->CallWriter = $reWriter->process();
327            break;
328            case DOKU_LEXER_MATCHED:
329                $this->_addCall('preformatted_newline',array(), $pos);
330            break;
331            case DOKU_LEXER_UNMATCHED:
332                $this->_addCall('preformatted_content',array($match), $pos);
333            break;
334        }
335
336        return true;
337    }
338
339    function quote($match, $state, $pos) {
340
341        switch ( $state ) {
342
343            case DOKU_LEXER_ENTER:
344                $this->CallWriter = new Quote($this->CallWriter);
345                $this->_addCall('quote_start',array($match), $pos);
346            break;
347
348            case DOKU_LEXER_EXIT:
349                $this->_addCall('quote_end',array(), $pos);
350                /** @var Lists $reWriter */
351                $reWriter = $this->CallWriter;
352                $this->CallWriter = $reWriter->process();
353            break;
354
355            case DOKU_LEXER_MATCHED:
356                $this->_addCall('quote_newline',array($match), $pos);
357            break;
358
359            case DOKU_LEXER_UNMATCHED:
360                $this->_addCall('cdata',array($match), $pos);
361            break;
362
363        }
364
365        return true;
366    }
367
368    /**
369     * Internal function for parsing highlight options.
370     * $options is parsed for key value pairs separated by commas.
371     * A value might also be missing in which case the value will simple
372     * be set to true. Commas in strings are ignored, e.g. option="4,56"
373     * will work as expected and will only create one entry.
374     *
375     * @param string $options space separated list of key-value pairs,
376     *                        e.g. option1=123, option2="456"
377     * @return array|null     Array of key-value pairs $array['key'] = 'value';
378     *                        or null if no entries found
379     */
380    protected function parse_highlight_options ($options) {
381        $result = array();
382        preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER);
383        foreach ($matches as $match) {
384            $equal_sign = strpos($match [0], '=');
385            if ($equal_sign === false) {
386                $key = trim($match[0]);
387                $result [$key] = 1;
388            } else {
389                $key = substr($match[0], 0, $equal_sign);
390                $value = substr($match[0], $equal_sign+1);
391                $value = trim($value, '"');
392                if (strlen($value) > 0) {
393                    $result [$key] = $value;
394                } else {
395                    $result [$key] = 1;
396                }
397            }
398        }
399
400        // Check for supported options
401        $result = array_intersect_key(
402            $result,
403            array_flip(array(
404                'enable_line_numbers',
405                'start_line_numbers_at',
406                'highlight_lines_extra',
407                'enable_keyword_links')
408            )
409        );
410
411        // Sanitize values
412        if(isset($result['enable_line_numbers'])) {
413            if($result['enable_line_numbers'] === 'false') {
414                $result['enable_line_numbers'] = false;
415            }
416            $result['enable_line_numbers'] = (bool) $result['enable_line_numbers'];
417        }
418        if(isset($result['highlight_lines_extra'])) {
419            $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra']));
420            $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']);
421            $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']);
422        }
423        if(isset($result['start_line_numbers_at'])) {
424            $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at'];
425        }
426        if(isset($result['enable_keyword_links'])) {
427            if($result['enable_keyword_links'] === 'false') {
428                $result['enable_keyword_links'] = false;
429            }
430            $result['enable_keyword_links'] = (bool) $result['enable_keyword_links'];
431        }
432        if (count($result) == 0) {
433            return null;
434        }
435
436        return $result;
437    }
438
439    function file($match, $state, $pos) {
440        return $this->code($match, $state, $pos, 'file');
441    }
442
443    function code($match, $state, $pos, $type='code') {
444        if ( $state == DOKU_LEXER_UNMATCHED ) {
445            $matches = explode('>',$match,2);
446            // Cut out variable options enclosed in []
447            preg_match('/\[.*\]/', $matches[0], $options);
448            if (!empty($options[0])) {
449                $matches[0] = str_replace($options[0], '', $matches[0]);
450            }
451            $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY);
452            while(count($param) < 2) array_push($param, null);
453            // We shortcut html here.
454            if ($param[0] == 'html') $param[0] = 'html4strict';
455            if ($param[0] == '-') $param[0] = null;
456            array_unshift($param, $matches[1]);
457            if (!empty($options[0])) {
458                $param [] = $this->parse_highlight_options ($options[0]);
459            }
460            $this->_addCall($type, $param, $pos);
461        }
462        return true;
463    }
464
465    function acronym($match, $state, $pos) {
466        $this->_addCall('acronym',array($match), $pos);
467        return true;
468    }
469
470    function smiley($match, $state, $pos) {
471        $this->_addCall('smiley',array($match), $pos);
472        return true;
473    }
474
475    function wordblock($match, $state, $pos) {
476        $this->_addCall('wordblock',array($match), $pos);
477        return true;
478    }
479
480    function entity($match, $state, $pos) {
481        $this->_addCall('entity',array($match), $pos);
482        return true;
483    }
484
485    function multiplyentity($match, $state, $pos) {
486        preg_match_all('/\d+/',$match,$matches);
487        $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos);
488        return true;
489    }
490
491    function singlequoteopening($match, $state, $pos) {
492        $this->_addCall('singlequoteopening',array(), $pos);
493        return true;
494    }
495
496    function singlequoteclosing($match, $state, $pos) {
497        $this->_addCall('singlequoteclosing',array(), $pos);
498        return true;
499    }
500
501    function apostrophe($match, $state, $pos) {
502        $this->_addCall('apostrophe',array(), $pos);
503        return true;
504    }
505
506    function doublequoteopening($match, $state, $pos) {
507        $this->_addCall('doublequoteopening',array(), $pos);
508        $this->status['doublequote']++;
509        return true;
510    }
511
512    function doublequoteclosing($match, $state, $pos) {
513        if ($this->status['doublequote'] <= 0) {
514            $this->doublequoteopening($match, $state, $pos);
515        } else {
516            $this->_addCall('doublequoteclosing',array(), $pos);
517            $this->status['doublequote'] = max(0, --$this->status['doublequote']);
518        }
519        return true;
520    }
521
522    function camelcaselink($match, $state, $pos) {
523        $this->_addCall('camelcaselink',array($match), $pos);
524        return true;
525    }
526
527    /*
528    */
529    function internallink($match, $state, $pos) {
530        // Strip the opening and closing markup
531        $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match);
532
533        // Split title from URL
534        $link = explode('|',$link,2);
535        if ( !isset($link[1]) ) {
536            $link[1] = null;
537        } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) {
538            // If the title is an image, convert it to an array containing the image details
539            $link[1] = Doku_Handler_Parse_Media($link[1]);
540        }
541        $link[0] = trim($link[0]);
542
543        //decide which kind of link it is
544
545        if ( link_isinterwiki($link[0]) ) {
546            // Interwiki
547            $interwiki = explode('>',$link[0],2);
548            $this->_addCall(
549                'interwikilink',
550                array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]),
551                $pos
552                );
553        }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) {
554            // Windows Share
555            $this->_addCall(
556                'windowssharelink',
557                array($link[0],$link[1]),
558                $pos
559                );
560        }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) {
561            // external link (accepts all protocols)
562            $this->_addCall(
563                    'externallink',
564                    array($link[0],$link[1]),
565                    $pos
566                    );
567        }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) {
568            // E-Mail (pattern above is defined in inc/mail.php)
569            $this->_addCall(
570                'emaillink',
571                array($link[0],$link[1]),
572                $pos
573                );
574        }elseif ( preg_match('!^#.+!',$link[0]) ){
575            // local link
576            $this->_addCall(
577                'locallink',
578                array(substr($link[0],1),$link[1]),
579                $pos
580                );
581        }else{
582            // internal link
583            $this->_addCall(
584                'internallink',
585                array($link[0],$link[1]),
586                $pos
587                );
588        }
589
590        return true;
591    }
592
593    function filelink($match, $state, $pos) {
594        $this->_addCall('filelink',array($match, null), $pos);
595        return true;
596    }
597
598    function windowssharelink($match, $state, $pos) {
599        $this->_addCall('windowssharelink',array($match, null), $pos);
600        return true;
601    }
602
603    function media($match, $state, $pos) {
604        $p = Doku_Handler_Parse_Media($match);
605
606        $this->_addCall(
607              $p['type'],
608              array($p['src'], $p['title'], $p['align'], $p['width'],
609                     $p['height'], $p['cache'], $p['linking']),
610              $pos
611             );
612        return true;
613    }
614
615    function rss($match, $state, $pos) {
616        $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match);
617
618        // get params
619        list($link,$params) = explode(' ',$link,2);
620
621        $p = array();
622        if(preg_match('/\b(\d+)\b/',$params,$match)){
623            $p['max'] = $match[1];
624        }else{
625            $p['max'] = 8;
626        }
627        $p['reverse'] = (preg_match('/rev/',$params));
628        $p['author']  = (preg_match('/\b(by|author)/',$params));
629        $p['date']    = (preg_match('/\b(date)/',$params));
630        $p['details'] = (preg_match('/\b(desc|detail)/',$params));
631        $p['nosort']  = (preg_match('/\b(nosort)\b/',$params));
632
633        if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) {
634            $period = array('d' => 86400, 'h' => 3600, 'm' => 60);
635            $p['refresh'] = max(600,$match[1]*$period[$match[2]]);  // n * period in seconds, minimum 10 minutes
636        } else {
637            $p['refresh'] = 14400;   // default to 4 hours
638        }
639
640        $this->_addCall('rss',array($link,$p),$pos);
641        return true;
642    }
643
644    function externallink($match, $state, $pos) {
645        $url   = $match;
646        $title = null;
647
648        // add protocol on simple short URLs
649        if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){
650            $title = $url;
651            $url   = 'ftp://'.$url;
652        }
653        if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){
654            $title = $url;
655            $url = 'http://'.$url;
656        }
657
658        $this->_addCall('externallink',array($url, $title), $pos);
659        return true;
660    }
661
662    function emaillink($match, $state, $pos) {
663        $email = preg_replace(array('/^</','/>$/'),'',$match);
664        $this->_addCall('emaillink',array($email, null), $pos);
665        return true;
666    }
667
668    function table($match, $state, $pos) {
669        switch ( $state ) {
670
671            case DOKU_LEXER_ENTER:
672
673                $this->CallWriter = new Table($this->CallWriter);
674
675                $this->_addCall('table_start', array($pos + 1), $pos);
676                if ( trim($match) == '^' ) {
677                    $this->_addCall('tableheader', array(), $pos);
678                } else {
679                    $this->_addCall('tablecell', array(), $pos);
680                }
681            break;
682
683            case DOKU_LEXER_EXIT:
684                $this->_addCall('table_end', array($pos), $pos);
685                /** @var Table $reWriter */
686                $reWriter = $this->CallWriter;
687                $this->CallWriter = $reWriter->process();
688            break;
689
690            case DOKU_LEXER_UNMATCHED:
691                if ( trim($match) != '' ) {
692                    $this->_addCall('cdata',array($match), $pos);
693                }
694            break;
695
696            case DOKU_LEXER_MATCHED:
697                if ( $match == ' ' ){
698                    $this->_addCall('cdata', array($match), $pos);
699                } else if ( preg_match('/:::/',$match) ) {
700                    $this->_addCall('rowspan', array($match), $pos);
701                } else if ( preg_match('/\t+/',$match) ) {
702                    $this->_addCall('table_align', array($match), $pos);
703                } else if ( preg_match('/ {2,}/',$match) ) {
704                    $this->_addCall('table_align', array($match), $pos);
705                } else if ( $match == "\n|" ) {
706                    $this->_addCall('table_row', array(), $pos);
707                    $this->_addCall('tablecell', array(), $pos);
708                } else if ( $match == "\n^" ) {
709                    $this->_addCall('table_row', array(), $pos);
710                    $this->_addCall('tableheader', array(), $pos);
711                } else if ( $match == '|' ) {
712                    $this->_addCall('tablecell', array(), $pos);
713                } else if ( $match == '^' ) {
714                    $this->_addCall('tableheader', array(), $pos);
715                }
716            break;
717        }
718        return true;
719    }
720}
721
722//------------------------------------------------------------------------
723function Doku_Handler_Parse_Media($match) {
724
725    // Strip the opening and closing markup
726    $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match);
727
728    // Split title from URL
729    $link = explode('|',$link,2);
730
731    // Check alignment
732    $ralign = (bool)preg_match('/^ /',$link[0]);
733    $lalign = (bool)preg_match('/ $/',$link[0]);
734
735    // Logic = what's that ;)...
736    if ( $lalign & $ralign ) {
737        $align = 'center';
738    } else if ( $ralign ) {
739        $align = 'right';
740    } else if ( $lalign ) {
741        $align = 'left';
742    } else {
743        $align = null;
744    }
745
746    // The title...
747    if ( !isset($link[1]) ) {
748        $link[1] = null;
749    }
750
751    //remove aligning spaces
752    $link[0] = trim($link[0]);
753
754    //split into src and parameters (using the very last questionmark)
755    $pos = strrpos($link[0], '?');
756    if($pos !== false){
757        $src   = substr($link[0],0,$pos);
758        $param = substr($link[0],$pos+1);
759    }else{
760        $src   = $link[0];
761        $param = '';
762    }
763
764    //parse width and height
765    if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){
766        !empty($size[1]) ? $w = $size[1] : $w = null;
767        !empty($size[3]) ? $h = $size[3] : $h = null;
768    } else {
769        $w = null;
770        $h = null;
771    }
772
773    //get linking command
774    if(preg_match('/nolink/i',$param)){
775        $linking = 'nolink';
776    }else if(preg_match('/direct/i',$param)){
777        $linking = 'direct';
778    }else if(preg_match('/linkonly/i',$param)){
779        $linking = 'linkonly';
780    }else{
781        $linking = 'details';
782    }
783
784    //get caching command
785    if (preg_match('/(nocache|recache)/i',$param,$cachemode)){
786        $cache = $cachemode[1];
787    }else{
788        $cache = 'cache';
789    }
790
791    // Check whether this is a local or remote image or interwiki
792    if (media_isexternal($src) || link_isinterwiki($src)){
793        $call = 'externalmedia';
794    } else {
795        $call = 'internalmedia';
796    }
797
798    $params = array(
799        'type'=>$call,
800        'src'=>$src,
801        'title'=>$link[1],
802        'align'=>$align,
803        'width'=>$w,
804        'height'=>$h,
805        'cache'=>$cache,
806        'linking'=>$linking,
807    );
808
809    return $params;
810}
811
812
813
814//Setup VIM: ex: et ts=4 :
815