These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | use dokuwiki\Extension\Event; |
||
4 | use dokuwiki\Extension\SyntaxPlugin; |
||
5 | use dokuwiki\Parsing\Handler\Block; |
||
6 | use dokuwiki\Parsing\Handler\CallWriter; |
||
7 | use dokuwiki\Parsing\Handler\CallWriterInterface; |
||
8 | use dokuwiki\Parsing\Handler\Lists; |
||
9 | use dokuwiki\Parsing\Handler\Nest; |
||
10 | use dokuwiki\Parsing\Handler\Preformatted; |
||
11 | use dokuwiki\Parsing\Handler\Quote; |
||
12 | use dokuwiki\Parsing\Handler\Table; |
||
13 | |||
14 | /** |
||
15 | * Class Doku_Handler |
||
16 | */ |
||
17 | class Doku_Handler { |
||
18 | /** @var CallWriterInterface */ |
||
19 | protected $callWriter = null; |
||
20 | |||
21 | /** @var array The current CallWriter will write directly to this list of calls, Parser reads it */ |
||
22 | public $calls = array(); |
||
23 | |||
24 | /** @var array internal status holders for some modes */ |
||
25 | protected $status = array( |
||
26 | 'section' => false, |
||
27 | 'doublequote' => 0, |
||
28 | ); |
||
29 | |||
30 | /** @var bool should blocks be rewritten? FIXME seems to always be true */ |
||
31 | protected $rewriteBlocks = true; |
||
32 | |||
33 | /** |
||
34 | * Doku_Handler constructor. |
||
35 | */ |
||
36 | public function __construct() { |
||
37 | $this->callWriter = new CallWriter($this); |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * Add a new call by passing it to the current CallWriter |
||
42 | * |
||
43 | * @param string $handler handler method name (see mode handlers below) |
||
44 | * @param mixed $args arguments for this call |
||
45 | * @param int $pos byte position in the original source file |
||
46 | */ |
||
47 | protected function addCall($handler, $args, $pos) { |
||
48 | $call = array($handler,$args, $pos); |
||
49 | $this->callWriter->writeCall($call); |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Similar to addCall, but adds a plugin call |
||
54 | * |
||
55 | * @param string $plugin name of the plugin |
||
56 | * @param mixed $args arguments for this call |
||
57 | * @param int $state a LEXER_STATE_* constant |
||
58 | * @param int $pos byte position in the original source file |
||
59 | * @param string $match matched syntax |
||
60 | */ |
||
61 | protected function addPluginCall($plugin, $args, $state, $pos, $match) { |
||
62 | $call = array('plugin',array($plugin, $args, $state, $match), $pos); |
||
63 | $this->callWriter->writeCall($call); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Finishes handling |
||
68 | * |
||
69 | * Called from the parser. Calls finalise() on the call writer, closes open |
||
70 | * sections, rewrites blocks and adds document_start and document_end calls. |
||
71 | * |
||
72 | * @triggers PARSER_HANDLER_DONE |
||
73 | */ |
||
74 | public function finalize(){ |
||
75 | $this->callWriter->finalise(); |
||
76 | |||
77 | if ( $this->status['section'] ) { |
||
78 | $last_call = end($this->calls); |
||
79 | array_push($this->calls,array('section_close',array(), $last_call[2])); |
||
80 | } |
||
81 | |||
82 | if ( $this->rewriteBlocks ) { |
||
83 | $B = new Block(); |
||
84 | $this->calls = $B->process($this->calls); |
||
85 | } |
||
86 | |||
87 | Event::createAndTrigger('PARSER_HANDLER_DONE',$this); |
||
88 | |||
89 | array_unshift($this->calls,array('document_start',array(),0)); |
||
90 | $last_call = end($this->calls); |
||
91 | array_push($this->calls,array('document_end',array(),$last_call[2])); |
||
92 | } |
||
93 | |||
94 | /** |
||
95 | * fetch the current call and advance the pointer to the next one |
||
96 | * |
||
97 | * @fixme seems to be unused? |
||
98 | * @return bool|mixed |
||
99 | */ |
||
100 | public function fetch() { |
||
101 | $call = current($this->calls); |
||
102 | if($call !== false) { |
||
103 | next($this->calls); //advance the pointer |
||
104 | return $call; |
||
105 | } |
||
106 | return false; |
||
107 | } |
||
108 | |||
109 | |||
110 | /** |
||
111 | * Internal function for parsing highlight options. |
||
112 | * $options is parsed for key value pairs separated by commas. |
||
113 | * A value might also be missing in which case the value will simple |
||
114 | * be set to true. Commas in strings are ignored, e.g. option="4,56" |
||
115 | * will work as expected and will only create one entry. |
||
116 | * |
||
117 | * @param string $options space separated list of key-value pairs, |
||
118 | * e.g. option1=123, option2="456" |
||
119 | * @return array|null Array of key-value pairs $array['key'] = 'value'; |
||
120 | * or null if no entries found |
||
121 | */ |
||
122 | protected function parse_highlight_options($options) { |
||
123 | $result = array(); |
||
124 | preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER); |
||
125 | foreach ($matches as $match) { |
||
126 | $equal_sign = strpos($match [0], '='); |
||
127 | if ($equal_sign === false) { |
||
128 | $key = trim($match[0]); |
||
129 | $result [$key] = 1; |
||
130 | } else { |
||
131 | $key = substr($match[0], 0, $equal_sign); |
||
132 | $value = substr($match[0], $equal_sign+1); |
||
133 | $value = trim($value, '"'); |
||
134 | if (strlen($value) > 0) { |
||
135 | $result [$key] = $value; |
||
136 | } else { |
||
137 | $result [$key] = 1; |
||
138 | } |
||
139 | } |
||
140 | } |
||
141 | |||
142 | // Check for supported options |
||
143 | $result = array_intersect_key( |
||
144 | $result, |
||
145 | array_flip(array( |
||
146 | 'enable_line_numbers', |
||
147 | 'start_line_numbers_at', |
||
148 | 'highlight_lines_extra', |
||
149 | 'enable_keyword_links') |
||
150 | ) |
||
151 | ); |
||
152 | |||
153 | // Sanitize values |
||
154 | if(isset($result['enable_line_numbers'])) { |
||
155 | if($result['enable_line_numbers'] === 'false') { |
||
156 | $result['enable_line_numbers'] = false; |
||
157 | } |
||
158 | $result['enable_line_numbers'] = (bool) $result['enable_line_numbers']; |
||
159 | } |
||
160 | if(isset($result['highlight_lines_extra'])) { |
||
161 | $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra'])); |
||
162 | $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']); |
||
163 | $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']); |
||
164 | } |
||
165 | if(isset($result['start_line_numbers_at'])) { |
||
166 | $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at']; |
||
167 | } |
||
168 | if(isset($result['enable_keyword_links'])) { |
||
169 | if($result['enable_keyword_links'] === 'false') { |
||
170 | $result['enable_keyword_links'] = false; |
||
171 | } |
||
172 | $result['enable_keyword_links'] = (bool) $result['enable_keyword_links']; |
||
173 | } |
||
174 | if (count($result) == 0) { |
||
175 | return null; |
||
176 | } |
||
177 | |||
178 | return $result; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Simplifies handling for the formatting tags which all behave the same |
||
183 | * |
||
184 | * @param string $match matched syntax |
||
185 | * @param int $state a LEXER_STATE_* constant |
||
186 | * @param int $pos byte position in the original source file |
||
187 | * @param string $name actual mode name |
||
188 | */ |
||
189 | protected function nestingTag($match, $state, $pos, $name) { |
||
190 | switch ( $state ) { |
||
191 | case DOKU_LEXER_ENTER: |
||
192 | $this->addCall($name.'_open', array(), $pos); |
||
193 | break; |
||
194 | case DOKU_LEXER_EXIT: |
||
195 | $this->addCall($name.'_close', array(), $pos); |
||
196 | break; |
||
197 | case DOKU_LEXER_UNMATCHED: |
||
198 | $this->addCall('cdata', array($match), $pos); |
||
199 | break; |
||
200 | } |
||
201 | } |
||
202 | |||
203 | |||
204 | /** |
||
205 | * The following methods define the handlers for the different Syntax modes |
||
206 | * |
||
207 | * The handlers are called from dokuwiki\Parsing\Lexer\Lexer\invokeParser() |
||
208 | * |
||
209 | * @todo it might make sense to move these into their own class or merge them with the |
||
210 | * ParserMode classes some time. |
||
211 | */ |
||
212 | // region mode handlers |
||
213 | |||
214 | /** |
||
215 | * Special plugin handler |
||
216 | * |
||
217 | * This handler is called for all modes starting with 'plugin_'. |
||
218 | * An additional parameter with the plugin name is passed. The plugin's handle() |
||
219 | * method is called here |
||
220 | * |
||
221 | * @author Andreas Gohr <[email protected]> |
||
222 | * |
||
223 | * @param string $match matched syntax |
||
224 | * @param int $state a LEXER_STATE_* constant |
||
225 | * @param int $pos byte position in the original source file |
||
226 | * @param string $pluginname name of the plugin |
||
227 | * @return bool mode handled? |
||
228 | */ |
||
229 | public function plugin($match, $state, $pos, $pluginname){ |
||
230 | $data = array($match); |
||
231 | /** @var SyntaxPlugin $plugin */ |
||
232 | $plugin = plugin_load('syntax',$pluginname); |
||
0 ignored issues
–
show
|
|||
233 | if($plugin != null){ |
||
234 | $data = $plugin->handle($match, $state, $pos, $this); |
||
235 | } |
||
236 | if ($data !== false) { |
||
237 | $this->addPluginCall($pluginname,$data,$state,$pos,$match); |
||
238 | } |
||
239 | return true; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * @param string $match matched syntax |
||
244 | * @param int $state a LEXER_STATE_* constant |
||
245 | * @param int $pos byte position in the original source file |
||
246 | * @return bool mode handled? |
||
247 | */ |
||
248 | public function base($match, $state, $pos) { |
||
249 | switch ( $state ) { |
||
250 | case DOKU_LEXER_UNMATCHED: |
||
251 | $this->addCall('cdata', array($match), $pos); |
||
252 | return true; |
||
253 | break; |
||
254 | } |
||
255 | return false; |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * @param string $match matched syntax |
||
260 | * @param int $state a LEXER_STATE_* constant |
||
261 | * @param int $pos byte position in the original source file |
||
262 | * @return bool mode handled? |
||
263 | */ |
||
264 | public function header($match, $state, $pos) { |
||
265 | // get level and title |
||
266 | $title = trim($match); |
||
267 | $level = 7 - strspn($title,'='); |
||
268 | if($level < 1) $level = 1; |
||
269 | $title = trim($title,'='); |
||
270 | $title = trim($title); |
||
271 | |||
272 | if ($this->status['section']) $this->addCall('section_close', array(), $pos); |
||
273 | |||
274 | $this->addCall('header', array($title, $level, $pos), $pos); |
||
275 | |||
276 | $this->addCall('section_open', array($level), $pos); |
||
277 | $this->status['section'] = true; |
||
278 | return true; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * @param string $match matched syntax |
||
283 | * @param int $state a LEXER_STATE_* constant |
||
284 | * @param int $pos byte position in the original source file |
||
285 | * @return bool mode handled? |
||
286 | */ |
||
287 | public function notoc($match, $state, $pos) { |
||
288 | $this->addCall('notoc', array(), $pos); |
||
289 | return true; |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * @param string $match matched syntax |
||
294 | * @param int $state a LEXER_STATE_* constant |
||
295 | * @param int $pos byte position in the original source file |
||
296 | * @return bool mode handled? |
||
297 | */ |
||
298 | public function nocache($match, $state, $pos) { |
||
299 | $this->addCall('nocache', array(), $pos); |
||
300 | return true; |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * @param string $match matched syntax |
||
305 | * @param int $state a LEXER_STATE_* constant |
||
306 | * @param int $pos byte position in the original source file |
||
307 | * @return bool mode handled? |
||
308 | */ |
||
309 | public function linebreak($match, $state, $pos) { |
||
310 | $this->addCall('linebreak', array(), $pos); |
||
311 | return true; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * @param string $match matched syntax |
||
316 | * @param int $state a LEXER_STATE_* constant |
||
317 | * @param int $pos byte position in the original source file |
||
318 | * @return bool mode handled? |
||
319 | */ |
||
320 | public function eol($match, $state, $pos) { |
||
321 | $this->addCall('eol', array(), $pos); |
||
322 | return true; |
||
323 | } |
||
324 | |||
325 | /** |
||
326 | * @param string $match matched syntax |
||
327 | * @param int $state a LEXER_STATE_* constant |
||
328 | * @param int $pos byte position in the original source file |
||
329 | * @return bool mode handled? |
||
330 | */ |
||
331 | public function hr($match, $state, $pos) { |
||
332 | $this->addCall('hr', array(), $pos); |
||
333 | return true; |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * @param string $match matched syntax |
||
338 | * @param int $state a LEXER_STATE_* constant |
||
339 | * @param int $pos byte position in the original source file |
||
340 | * @return bool mode handled? |
||
341 | */ |
||
342 | public function strong($match, $state, $pos) { |
||
343 | $this->nestingTag($match, $state, $pos, 'strong'); |
||
344 | return true; |
||
345 | } |
||
346 | |||
347 | /** |
||
348 | * @param string $match matched syntax |
||
349 | * @param int $state a LEXER_STATE_* constant |
||
350 | * @param int $pos byte position in the original source file |
||
351 | * @return bool mode handled? |
||
352 | */ |
||
353 | public function emphasis($match, $state, $pos) { |
||
354 | $this->nestingTag($match, $state, $pos, 'emphasis'); |
||
355 | return true; |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * @param string $match matched syntax |
||
360 | * @param int $state a LEXER_STATE_* constant |
||
361 | * @param int $pos byte position in the original source file |
||
362 | * @return bool mode handled? |
||
363 | */ |
||
364 | public function underline($match, $state, $pos) { |
||
365 | $this->nestingTag($match, $state, $pos, 'underline'); |
||
366 | return true; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * @param string $match matched syntax |
||
371 | * @param int $state a LEXER_STATE_* constant |
||
372 | * @param int $pos byte position in the original source file |
||
373 | * @return bool mode handled? |
||
374 | */ |
||
375 | public function monospace($match, $state, $pos) { |
||
376 | $this->nestingTag($match, $state, $pos, 'monospace'); |
||
377 | return true; |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * @param string $match matched syntax |
||
382 | * @param int $state a LEXER_STATE_* constant |
||
383 | * @param int $pos byte position in the original source file |
||
384 | * @return bool mode handled? |
||
385 | */ |
||
386 | public function subscript($match, $state, $pos) { |
||
387 | $this->nestingTag($match, $state, $pos, 'subscript'); |
||
388 | return true; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * @param string $match matched syntax |
||
393 | * @param int $state a LEXER_STATE_* constant |
||
394 | * @param int $pos byte position in the original source file |
||
395 | * @return bool mode handled? |
||
396 | */ |
||
397 | public function superscript($match, $state, $pos) { |
||
398 | $this->nestingTag($match, $state, $pos, 'superscript'); |
||
399 | return true; |
||
400 | } |
||
401 | |||
402 | /** |
||
403 | * @param string $match matched syntax |
||
404 | * @param int $state a LEXER_STATE_* constant |
||
405 | * @param int $pos byte position in the original source file |
||
406 | * @return bool mode handled? |
||
407 | */ |
||
408 | public function deleted($match, $state, $pos) { |
||
409 | $this->nestingTag($match, $state, $pos, 'deleted'); |
||
410 | return true; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * @param string $match matched syntax |
||
415 | * @param int $state a LEXER_STATE_* constant |
||
416 | * @param int $pos byte position in the original source file |
||
417 | * @return bool mode handled? |
||
418 | */ |
||
419 | public function footnote($match, $state, $pos) { |
||
420 | if (!isset($this->_footnote)) $this->_footnote = false; |
||
421 | |||
422 | switch ( $state ) { |
||
423 | case DOKU_LEXER_ENTER: |
||
424 | // footnotes can not be nested - however due to limitations in lexer it can't be prevented |
||
425 | // we will still enter a new footnote mode, we just do nothing |
||
426 | if ($this->_footnote) { |
||
427 | $this->addCall('cdata', array($match), $pos); |
||
428 | break; |
||
429 | } |
||
430 | $this->_footnote = true; |
||
431 | |||
432 | $this->callWriter = new Nest($this->callWriter, 'footnote_close'); |
||
433 | $this->addCall('footnote_open', array(), $pos); |
||
434 | break; |
||
435 | case DOKU_LEXER_EXIT: |
||
436 | // check whether we have already exitted the footnote mode, can happen if the modes were nested |
||
437 | if (!$this->_footnote) { |
||
438 | $this->addCall('cdata', array($match), $pos); |
||
439 | break; |
||
440 | } |
||
441 | |||
442 | $this->_footnote = false; |
||
443 | $this->addCall('footnote_close', array(), $pos); |
||
444 | |||
445 | /** @var Nest $reWriter */ |
||
446 | $reWriter = $this->callWriter; |
||
447 | $this->callWriter = $reWriter->process(); |
||
448 | break; |
||
449 | case DOKU_LEXER_UNMATCHED: |
||
450 | $this->addCall('cdata', array($match), $pos); |
||
451 | break; |
||
452 | } |
||
453 | return true; |
||
454 | } |
||
455 | |||
456 | /** |
||
457 | * @param string $match matched syntax |
||
458 | * @param int $state a LEXER_STATE_* constant |
||
459 | * @param int $pos byte position in the original source file |
||
460 | * @return bool mode handled? |
||
461 | */ |
||
462 | public function listblock($match, $state, $pos) { |
||
463 | switch ( $state ) { |
||
464 | case DOKU_LEXER_ENTER: |
||
465 | $this->callWriter = new Lists($this->callWriter); |
||
466 | $this->addCall('list_open', array($match), $pos); |
||
467 | break; |
||
468 | case DOKU_LEXER_EXIT: |
||
469 | $this->addCall('list_close', array(), $pos); |
||
470 | /** @var Lists $reWriter */ |
||
471 | $reWriter = $this->callWriter; |
||
472 | $this->callWriter = $reWriter->process(); |
||
473 | break; |
||
474 | case DOKU_LEXER_MATCHED: |
||
475 | $this->addCall('list_item', array($match), $pos); |
||
476 | break; |
||
477 | case DOKU_LEXER_UNMATCHED: |
||
478 | $this->addCall('cdata', array($match), $pos); |
||
479 | break; |
||
480 | } |
||
481 | return true; |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * @param string $match matched syntax |
||
486 | * @param int $state a LEXER_STATE_* constant |
||
487 | * @param int $pos byte position in the original source file |
||
488 | * @return bool mode handled? |
||
489 | */ |
||
490 | public function unformatted($match, $state, $pos) { |
||
491 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
492 | $this->addCall('unformatted', array($match), $pos); |
||
493 | } |
||
494 | return true; |
||
495 | } |
||
496 | |||
497 | /** |
||
498 | * @param string $match matched syntax |
||
499 | * @param int $state a LEXER_STATE_* constant |
||
500 | * @param int $pos byte position in the original source file |
||
501 | * @return bool mode handled? |
||
502 | */ |
||
503 | public function php($match, $state, $pos) { |
||
504 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
505 | $this->addCall('php', array($match), $pos); |
||
506 | } |
||
507 | return true; |
||
508 | } |
||
509 | |||
510 | /** |
||
511 | * @param string $match matched syntax |
||
512 | * @param int $state a LEXER_STATE_* constant |
||
513 | * @param int $pos byte position in the original source file |
||
514 | * @return bool mode handled? |
||
515 | */ |
||
516 | public function phpblock($match, $state, $pos) { |
||
517 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
518 | $this->addCall('phpblock', array($match), $pos); |
||
519 | } |
||
520 | return true; |
||
521 | } |
||
522 | |||
523 | /** |
||
524 | * @param string $match matched syntax |
||
525 | * @param int $state a LEXER_STATE_* constant |
||
526 | * @param int $pos byte position in the original source file |
||
527 | * @return bool mode handled? |
||
528 | */ |
||
529 | public function html($match, $state, $pos) { |
||
530 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
531 | $this->addCall('html', array($match), $pos); |
||
532 | } |
||
533 | return true; |
||
534 | } |
||
535 | |||
536 | /** |
||
537 | * @param string $match matched syntax |
||
538 | * @param int $state a LEXER_STATE_* constant |
||
539 | * @param int $pos byte position in the original source file |
||
540 | * @return bool mode handled? |
||
541 | */ |
||
542 | public function htmlblock($match, $state, $pos) { |
||
543 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
544 | $this->addCall('htmlblock', array($match), $pos); |
||
545 | } |
||
546 | return true; |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * @param string $match matched syntax |
||
551 | * @param int $state a LEXER_STATE_* constant |
||
552 | * @param int $pos byte position in the original source file |
||
553 | * @return bool mode handled? |
||
554 | */ |
||
555 | public function preformatted($match, $state, $pos) { |
||
556 | switch ( $state ) { |
||
557 | case DOKU_LEXER_ENTER: |
||
558 | $this->callWriter = new Preformatted($this->callWriter); |
||
559 | $this->addCall('preformatted_start', array(), $pos); |
||
560 | break; |
||
561 | case DOKU_LEXER_EXIT: |
||
562 | $this->addCall('preformatted_end', array(), $pos); |
||
563 | /** @var Preformatted $reWriter */ |
||
564 | $reWriter = $this->callWriter; |
||
565 | $this->callWriter = $reWriter->process(); |
||
566 | break; |
||
567 | case DOKU_LEXER_MATCHED: |
||
568 | $this->addCall('preformatted_newline', array(), $pos); |
||
569 | break; |
||
570 | case DOKU_LEXER_UNMATCHED: |
||
571 | $this->addCall('preformatted_content', array($match), $pos); |
||
572 | break; |
||
573 | } |
||
574 | |||
575 | return true; |
||
576 | } |
||
577 | |||
578 | /** |
||
579 | * @param string $match matched syntax |
||
580 | * @param int $state a LEXER_STATE_* constant |
||
581 | * @param int $pos byte position in the original source file |
||
582 | * @return bool mode handled? |
||
583 | */ |
||
584 | public function quote($match, $state, $pos) { |
||
585 | |||
586 | switch ( $state ) { |
||
587 | |||
588 | case DOKU_LEXER_ENTER: |
||
589 | $this->callWriter = new Quote($this->callWriter); |
||
590 | $this->addCall('quote_start', array($match), $pos); |
||
591 | break; |
||
592 | |||
593 | case DOKU_LEXER_EXIT: |
||
594 | $this->addCall('quote_end', array(), $pos); |
||
595 | /** @var Lists $reWriter */ |
||
596 | $reWriter = $this->callWriter; |
||
597 | $this->callWriter = $reWriter->process(); |
||
598 | break; |
||
599 | |||
600 | case DOKU_LEXER_MATCHED: |
||
601 | $this->addCall('quote_newline', array($match), $pos); |
||
602 | break; |
||
603 | |||
604 | case DOKU_LEXER_UNMATCHED: |
||
605 | $this->addCall('cdata', array($match), $pos); |
||
606 | break; |
||
607 | |||
608 | } |
||
609 | |||
610 | return true; |
||
611 | } |
||
612 | |||
613 | /** |
||
614 | * @param string $match matched syntax |
||
615 | * @param int $state a LEXER_STATE_* constant |
||
616 | * @param int $pos byte position in the original source file |
||
617 | * @return bool mode handled? |
||
618 | */ |
||
619 | public function file($match, $state, $pos) { |
||
620 | return $this->code($match, $state, $pos, 'file'); |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * @param string $match matched syntax |
||
625 | * @param int $state a LEXER_STATE_* constant |
||
626 | * @param int $pos byte position in the original source file |
||
627 | * @param string $type either 'code' or 'file' |
||
628 | * @return bool mode handled? |
||
629 | */ |
||
630 | public function code($match, $state, $pos, $type='code') { |
||
631 | if ( $state == DOKU_LEXER_UNMATCHED ) { |
||
632 | $matches = explode('>',$match,2); |
||
633 | // Cut out variable options enclosed in [] |
||
634 | preg_match('/\[.*\]/', $matches[0], $options); |
||
635 | if (!empty($options[0])) { |
||
636 | $matches[0] = str_replace($options[0], '', $matches[0]); |
||
637 | } |
||
638 | $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY); |
||
639 | while(count($param) < 2) array_push($param, null); |
||
640 | // We shortcut html here. |
||
641 | if ($param[0] == 'html') $param[0] = 'html4strict'; |
||
642 | if ($param[0] == '-') $param[0] = null; |
||
643 | array_unshift($param, $matches[1]); |
||
644 | if (!empty($options[0])) { |
||
645 | $param [] = $this->parse_highlight_options ($options[0]); |
||
646 | } |
||
647 | $this->addCall($type, $param, $pos); |
||
648 | } |
||
649 | return true; |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * @param string $match matched syntax |
||
654 | * @param int $state a LEXER_STATE_* constant |
||
655 | * @param int $pos byte position in the original source file |
||
656 | * @return bool mode handled? |
||
657 | */ |
||
658 | public function acronym($match, $state, $pos) { |
||
659 | $this->addCall('acronym', array($match), $pos); |
||
660 | return true; |
||
661 | } |
||
662 | |||
663 | /** |
||
664 | * @param string $match matched syntax |
||
665 | * @param int $state a LEXER_STATE_* constant |
||
666 | * @param int $pos byte position in the original source file |
||
667 | * @return bool mode handled? |
||
668 | */ |
||
669 | public function smiley($match, $state, $pos) { |
||
670 | $this->addCall('smiley', array($match), $pos); |
||
671 | return true; |
||
672 | } |
||
673 | |||
674 | /** |
||
675 | * @param string $match matched syntax |
||
676 | * @param int $state a LEXER_STATE_* constant |
||
677 | * @param int $pos byte position in the original source file |
||
678 | * @return bool mode handled? |
||
679 | */ |
||
680 | public function wordblock($match, $state, $pos) { |
||
681 | $this->addCall('wordblock', array($match), $pos); |
||
682 | return true; |
||
683 | } |
||
684 | |||
685 | /** |
||
686 | * @param string $match matched syntax |
||
687 | * @param int $state a LEXER_STATE_* constant |
||
688 | * @param int $pos byte position in the original source file |
||
689 | * @return bool mode handled? |
||
690 | */ |
||
691 | public function entity($match, $state, $pos) { |
||
692 | $this->addCall('entity', array($match), $pos); |
||
693 | return true; |
||
694 | } |
||
695 | |||
696 | /** |
||
697 | * @param string $match matched syntax |
||
698 | * @param int $state a LEXER_STATE_* constant |
||
699 | * @param int $pos byte position in the original source file |
||
700 | * @return bool mode handled? |
||
701 | */ |
||
702 | public function multiplyentity($match, $state, $pos) { |
||
703 | preg_match_all('/\d+/',$match,$matches); |
||
704 | $this->addCall('multiplyentity', array($matches[0][0], $matches[0][1]), $pos); |
||
705 | return true; |
||
706 | } |
||
707 | |||
708 | /** |
||
709 | * @param string $match matched syntax |
||
710 | * @param int $state a LEXER_STATE_* constant |
||
711 | * @param int $pos byte position in the original source file |
||
712 | * @return bool mode handled? |
||
713 | */ |
||
714 | public function singlequoteopening($match, $state, $pos) { |
||
715 | $this->addCall('singlequoteopening', array(), $pos); |
||
716 | return true; |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * @param string $match matched syntax |
||
721 | * @param int $state a LEXER_STATE_* constant |
||
722 | * @param int $pos byte position in the original source file |
||
723 | * @return bool mode handled? |
||
724 | */ |
||
725 | public function singlequoteclosing($match, $state, $pos) { |
||
726 | $this->addCall('singlequoteclosing', array(), $pos); |
||
727 | return true; |
||
728 | } |
||
729 | |||
730 | /** |
||
731 | * @param string $match matched syntax |
||
732 | * @param int $state a LEXER_STATE_* constant |
||
733 | * @param int $pos byte position in the original source file |
||
734 | * @return bool mode handled? |
||
735 | */ |
||
736 | public function apostrophe($match, $state, $pos) { |
||
737 | $this->addCall('apostrophe', array(), $pos); |
||
738 | return true; |
||
739 | } |
||
740 | |||
741 | /** |
||
742 | * @param string $match matched syntax |
||
743 | * @param int $state a LEXER_STATE_* constant |
||
744 | * @param int $pos byte position in the original source file |
||
745 | * @return bool mode handled? |
||
746 | */ |
||
747 | public function doublequoteopening($match, $state, $pos) { |
||
748 | $this->addCall('doublequoteopening', array(), $pos); |
||
749 | $this->status['doublequote']++; |
||
750 | return true; |
||
751 | } |
||
752 | |||
753 | /** |
||
754 | * @param string $match matched syntax |
||
755 | * @param int $state a LEXER_STATE_* constant |
||
756 | * @param int $pos byte position in the original source file |
||
757 | * @return bool mode handled? |
||
758 | */ |
||
759 | public function doublequoteclosing($match, $state, $pos) { |
||
760 | if ($this->status['doublequote'] <= 0) { |
||
761 | $this->doublequoteopening($match, $state, $pos); |
||
762 | } else { |
||
763 | $this->addCall('doublequoteclosing', array(), $pos); |
||
764 | $this->status['doublequote'] = max(0, --$this->status['doublequote']); |
||
765 | } |
||
766 | return true; |
||
767 | } |
||
768 | |||
769 | /** |
||
770 | * @param string $match matched syntax |
||
771 | * @param int $state a LEXER_STATE_* constant |
||
772 | * @param int $pos byte position in the original source file |
||
773 | * @return bool mode handled? |
||
774 | */ |
||
775 | public function camelcaselink($match, $state, $pos) { |
||
776 | $this->addCall('camelcaselink', array($match), $pos); |
||
777 | return true; |
||
778 | } |
||
779 | |||
780 | /** |
||
781 | * @param string $match matched syntax |
||
782 | * @param int $state a LEXER_STATE_* constant |
||
783 | * @param int $pos byte position in the original source file |
||
784 | * @return bool mode handled? |
||
785 | */ |
||
786 | public function internallink($match, $state, $pos) { |
||
787 | // Strip the opening and closing markup |
||
788 | $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); |
||
789 | |||
790 | // Split title from URL |
||
791 | $link = explode('|',$link,2); |
||
792 | if ( !isset($link[1]) ) { |
||
793 | $link[1] = null; |
||
794 | } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) { |
||
795 | // If the title is an image, convert it to an array containing the image details |
||
796 | $link[1] = Doku_Handler_Parse_Media($link[1]); |
||
797 | } |
||
798 | $link[0] = trim($link[0]); |
||
799 | |||
800 | //decide which kind of link it is |
||
801 | |||
802 | if ( link_isinterwiki($link[0]) ) { |
||
803 | // Interwiki |
||
804 | $interwiki = explode('>',$link[0],2); |
||
805 | $this->addCall( |
||
806 | 'interwikilink', |
||
807 | array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), |
||
808 | $pos |
||
809 | ); |
||
810 | }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { |
||
811 | // Windows Share |
||
812 | $this->addCall( |
||
813 | 'windowssharelink', |
||
814 | array($link[0],$link[1]), |
||
815 | $pos |
||
816 | ); |
||
817 | }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) { |
||
818 | // external link (accepts all protocols) |
||
819 | $this->addCall( |
||
820 | 'externallink', |
||
821 | array($link[0],$link[1]), |
||
822 | $pos |
||
823 | ); |
||
824 | }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) { |
||
825 | // E-Mail (pattern above is defined in inc/mail.php) |
||
826 | $this->addCall( |
||
827 | 'emaillink', |
||
828 | array($link[0],$link[1]), |
||
829 | $pos |
||
830 | ); |
||
831 | }elseif ( preg_match('!^#.+!',$link[0]) ){ |
||
832 | // local link |
||
833 | $this->addCall( |
||
834 | 'locallink', |
||
835 | array(substr($link[0],1),$link[1]), |
||
836 | $pos |
||
837 | ); |
||
838 | }else{ |
||
839 | // internal link |
||
840 | $this->addCall( |
||
841 | 'internallink', |
||
842 | array($link[0],$link[1]), |
||
843 | $pos |
||
844 | ); |
||
845 | } |
||
846 | |||
847 | return true; |
||
848 | } |
||
849 | |||
850 | /** |
||
851 | * @param string $match matched syntax |
||
852 | * @param int $state a LEXER_STATE_* constant |
||
853 | * @param int $pos byte position in the original source file |
||
854 | * @return bool mode handled? |
||
855 | */ |
||
856 | public function filelink($match, $state, $pos) { |
||
857 | $this->addCall('filelink', array($match, null), $pos); |
||
858 | return true; |
||
859 | } |
||
860 | |||
861 | /** |
||
862 | * @param string $match matched syntax |
||
863 | * @param int $state a LEXER_STATE_* constant |
||
864 | * @param int $pos byte position in the original source file |
||
865 | * @return bool mode handled? |
||
866 | */ |
||
867 | public function windowssharelink($match, $state, $pos) { |
||
868 | $this->addCall('windowssharelink', array($match, null), $pos); |
||
869 | return true; |
||
870 | } |
||
871 | |||
872 | /** |
||
873 | * @param string $match matched syntax |
||
874 | * @param int $state a LEXER_STATE_* constant |
||
875 | * @param int $pos byte position in the original source file |
||
876 | * @return bool mode handled? |
||
877 | */ |
||
878 | public function media($match, $state, $pos) { |
||
879 | $p = Doku_Handler_Parse_Media($match); |
||
880 | |||
881 | $this->addCall( |
||
882 | $p['type'], |
||
883 | array($p['src'], $p['title'], $p['align'], $p['width'], |
||
884 | $p['height'], $p['cache'], $p['linking']), |
||
885 | $pos |
||
886 | ); |
||
887 | return true; |
||
888 | } |
||
889 | |||
890 | /** |
||
891 | * @param string $match matched syntax |
||
892 | * @param int $state a LEXER_STATE_* constant |
||
893 | * @param int $pos byte position in the original source file |
||
894 | * @return bool mode handled? |
||
895 | */ |
||
896 | public function rss($match, $state, $pos) { |
||
897 | $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); |
||
898 | |||
899 | // get params |
||
900 | list($link,$params) = explode(' ',$link,2); |
||
901 | |||
902 | $p = array(); |
||
903 | if(preg_match('/\b(\d+)\b/',$params,$match)){ |
||
904 | $p['max'] = $match[1]; |
||
905 | }else{ |
||
906 | $p['max'] = 8; |
||
907 | } |
||
908 | $p['reverse'] = (preg_match('/rev/',$params)); |
||
909 | $p['author'] = (preg_match('/\b(by|author)/',$params)); |
||
910 | $p['date'] = (preg_match('/\b(date)/',$params)); |
||
911 | $p['details'] = (preg_match('/\b(desc|detail)/',$params)); |
||
912 | $p['nosort'] = (preg_match('/\b(nosort)\b/',$params)); |
||
913 | |||
914 | if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) { |
||
915 | $period = array('d' => 86400, 'h' => 3600, 'm' => 60); |
||
916 | $p['refresh'] = max(600,$match[1]*$period[$match[2]]); // n * period in seconds, minimum 10 minutes |
||
917 | } else { |
||
918 | $p['refresh'] = 14400; // default to 4 hours |
||
919 | } |
||
920 | |||
921 | $this->addCall('rss', array($link, $p), $pos); |
||
922 | return true; |
||
923 | } |
||
924 | |||
925 | /** |
||
926 | * @param string $match matched syntax |
||
927 | * @param int $state a LEXER_STATE_* constant |
||
928 | * @param int $pos byte position in the original source file |
||
929 | * @return bool mode handled? |
||
930 | */ |
||
931 | public function externallink($match, $state, $pos) { |
||
932 | $url = $match; |
||
933 | $title = null; |
||
934 | |||
935 | // add protocol on simple short URLs |
||
936 | if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){ |
||
937 | $title = $url; |
||
938 | $url = 'ftp://'.$url; |
||
939 | } |
||
940 | if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){ |
||
941 | $title = $url; |
||
942 | $url = 'http://'.$url; |
||
943 | } |
||
944 | |||
945 | $this->addCall('externallink', array($url, $title), $pos); |
||
946 | return true; |
||
947 | } |
||
948 | |||
949 | /** |
||
950 | * @param string $match matched syntax |
||
951 | * @param int $state a LEXER_STATE_* constant |
||
952 | * @param int $pos byte position in the original source file |
||
953 | * @return bool mode handled? |
||
954 | */ |
||
955 | public function emaillink($match, $state, $pos) { |
||
956 | $email = preg_replace(array('/^</','/>$/'),'',$match); |
||
957 | $this->addCall('emaillink', array($email, null), $pos); |
||
958 | return true; |
||
959 | } |
||
960 | |||
961 | /** |
||
962 | * @param string $match matched syntax |
||
963 | * @param int $state a LEXER_STATE_* constant |
||
964 | * @param int $pos byte position in the original source file |
||
965 | * @return bool mode handled? |
||
966 | */ |
||
967 | public function table($match, $state, $pos) { |
||
968 | switch ( $state ) { |
||
969 | |||
970 | case DOKU_LEXER_ENTER: |
||
971 | |||
972 | $this->callWriter = new Table($this->callWriter); |
||
973 | |||
974 | $this->addCall('table_start', array($pos + 1), $pos); |
||
975 | if ( trim($match) == '^' ) { |
||
976 | $this->addCall('tableheader', array(), $pos); |
||
977 | } else { |
||
978 | $this->addCall('tablecell', array(), $pos); |
||
979 | } |
||
980 | break; |
||
981 | |||
982 | case DOKU_LEXER_EXIT: |
||
983 | $this->addCall('table_end', array($pos), $pos); |
||
984 | /** @var Table $reWriter */ |
||
985 | $reWriter = $this->callWriter; |
||
986 | $this->callWriter = $reWriter->process(); |
||
987 | break; |
||
988 | |||
989 | case DOKU_LEXER_UNMATCHED: |
||
990 | if ( trim($match) != '' ) { |
||
991 | $this->addCall('cdata', array($match), $pos); |
||
992 | } |
||
993 | break; |
||
994 | |||
995 | case DOKU_LEXER_MATCHED: |
||
996 | if ( $match == ' ' ){ |
||
997 | $this->addCall('cdata', array($match), $pos); |
||
998 | } else if ( preg_match('/:::/',$match) ) { |
||
999 | $this->addCall('rowspan', array($match), $pos); |
||
1000 | } else if ( preg_match('/\t+/',$match) ) { |
||
1001 | $this->addCall('table_align', array($match), $pos); |
||
1002 | } else if ( preg_match('/ {2,}/',$match) ) { |
||
1003 | $this->addCall('table_align', array($match), $pos); |
||
1004 | } else if ( $match == "\n|" ) { |
||
1005 | $this->addCall('table_row', array(), $pos); |
||
1006 | $this->addCall('tablecell', array(), $pos); |
||
1007 | } else if ( $match == "\n^" ) { |
||
1008 | $this->addCall('table_row', array(), $pos); |
||
1009 | $this->addCall('tableheader', array(), $pos); |
||
1010 | } else if ( $match == '|' ) { |
||
1011 | $this->addCall('tablecell', array(), $pos); |
||
1012 | } else if ( $match == '^' ) { |
||
1013 | $this->addCall('tableheader', array(), $pos); |
||
1014 | } |
||
1015 | break; |
||
1016 | } |
||
1017 | return true; |
||
1018 | } |
||
1019 | |||
1020 | // endregion modes |
||
1021 | } |
||
1022 | |||
1023 | //------------------------------------------------------------------------ |
||
1024 | function Doku_Handler_Parse_Media($match) { |
||
1025 | |||
1026 | // Strip the opening and closing markup |
||
1027 | $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); |
||
1028 | |||
1029 | // Split title from URL |
||
1030 | $link = explode('|',$link,2); |
||
1031 | |||
1032 | // Check alignment |
||
1033 | $ralign = (bool)preg_match('/^ /',$link[0]); |
||
1034 | $lalign = (bool)preg_match('/ $/',$link[0]); |
||
1035 | |||
1036 | // Logic = what's that ;)... |
||
1037 | if ( $lalign & $ralign ) { |
||
1038 | $align = 'center'; |
||
1039 | } else if ( $ralign ) { |
||
1040 | $align = 'right'; |
||
1041 | } else if ( $lalign ) { |
||
1042 | $align = 'left'; |
||
1043 | } else { |
||
1044 | $align = null; |
||
1045 | } |
||
1046 | |||
1047 | // The title... |
||
1048 | if ( !isset($link[1]) ) { |
||
1049 | $link[1] = null; |
||
1050 | } |
||
1051 | |||
1052 | //remove aligning spaces |
||
1053 | $link[0] = trim($link[0]); |
||
1054 | |||
1055 | //split into src and parameters (using the very last questionmark) |
||
1056 | $pos = strrpos($link[0], '?'); |
||
1057 | if($pos !== false){ |
||
1058 | $src = substr($link[0],0,$pos); |
||
1059 | $param = substr($link[0],$pos+1); |
||
1060 | }else{ |
||
1061 | $src = $link[0]; |
||
1062 | $param = ''; |
||
1063 | } |
||
1064 | |||
1065 | //parse width and height |
||
1066 | if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){ |
||
1067 | !empty($size[1]) ? $w = $size[1] : $w = null; |
||
1068 | !empty($size[3]) ? $h = $size[3] : $h = null; |
||
1069 | } else { |
||
1070 | $w = null; |
||
1071 | $h = null; |
||
1072 | } |
||
1073 | |||
1074 | //get linking command |
||
1075 | if(preg_match('/nolink/i',$param)){ |
||
1076 | $linking = 'nolink'; |
||
1077 | }else if(preg_match('/direct/i',$param)){ |
||
1078 | $linking = 'direct'; |
||
1079 | }else if(preg_match('/linkonly/i',$param)){ |
||
1080 | $linking = 'linkonly'; |
||
1081 | }else{ |
||
1082 | $linking = 'details'; |
||
1083 | } |
||
1084 | |||
1085 | //get caching command |
||
1086 | if (preg_match('/(nocache|recache)/i',$param,$cachemode)){ |
||
1087 | $cache = $cachemode[1]; |
||
1088 | }else{ |
||
1089 | $cache = 'cache'; |
||
1090 | } |
||
1091 | |||
1092 | // Check whether this is a local or remote image or interwiki |
||
1093 | if (media_isexternal($src) || link_isinterwiki($src)){ |
||
1094 | $call = 'externalmedia'; |
||
1095 | } else { |
||
1096 | $call = 'internalmedia'; |
||
1097 | } |
||
1098 | |||
1099 | $params = array( |
||
1100 | 'type'=>$call, |
||
1101 | 'src'=>$src, |
||
1102 | 'title'=>$link[1], |
||
1103 | 'align'=>$align, |
||
1104 | 'width'=>$w, |
||
1105 | 'height'=>$h, |
||
1106 | 'cache'=>$cache, |
||
1107 | 'linking'=>$linking, |
||
1108 | ); |
||
1109 | |||
1110 | return $params; |
||
1111 | } |
||
1112 | |||
1113 |
This function has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.