10cecf9d5Sandi<?php 25c2aad12SAndreas Gohr 3cbb44eabSAndreas Gohruse dokuwiki\Extension\Event; 4e1d9dcc8SAndreas Gohruse dokuwiki\Extension\SyntaxPlugin; 5be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Block; 6be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\CallWriter; 7be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\CallWriterInterface; 8be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Lists; 9be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Nest; 10be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Preformatted; 11be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Quote; 12be906b56SAndreas Gohruse dokuwiki\Parsing\Handler\Table; 135c2aad12SAndreas Gohr 148b1b81beSAndreas Gohr/** 158b1b81beSAndreas Gohr * Class Doku_Handler 168b1b81beSAndreas Gohr */ 170cecf9d5Sandiclass Doku_Handler { 188b1b81beSAndreas Gohr /** @var CallWriterInterface */ 198b1b81beSAndreas Gohr protected $callWriter = null; 200cecf9d5Sandi 218b1b81beSAndreas Gohr /** @var array The current CallWriter will write directly to this list of calls, Parser reads it */ 228b1b81beSAndreas Gohr public $calls = array(); 230cecf9d5Sandi 248b1b81beSAndreas Gohr /** @var array internal status holders for some modes */ 258b1b81beSAndreas Gohr protected $status = array( 2644881bd0Shenning.noren 'section' => false, 27e950d12fSChristopher Smith 'doublequote' => 0, 280cecf9d5Sandi ); 290cecf9d5Sandi 308b1b81beSAndreas Gohr /** @var bool should blocks be rewritten? FIXME seems to always be true */ 318b1b81beSAndreas Gohr protected $rewriteBlocks = true; 32b7c441b9SHarry Fuecks 338b1b81beSAndreas Gohr /** 348b1b81beSAndreas Gohr * Doku_Handler constructor. 358b1b81beSAndreas Gohr */ 36e1cdd96cSAndreas Gohr public function __construct() { 378b1b81beSAndreas Gohr $this->callWriter = new CallWriter($this); 380cecf9d5Sandi } 390cecf9d5Sandi 40276820f7SScrutinizer Auto-Fixer /** 418b1b81beSAndreas Gohr * Add a new call by passing it to the current CallWriter 428b1b81beSAndreas Gohr * 438b1b81beSAndreas Gohr * @param string $handler handler method name (see mode handlers below) 448b1b81beSAndreas Gohr * @param mixed $args arguments for this call 458b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 46276820f7SScrutinizer Auto-Fixer */ 4731c0895aSAndreas Gohr public function addCall($handler, $args, $pos) { 480cecf9d5Sandi $call = array($handler,$args, $pos); 498b1b81beSAndreas Gohr $this->callWriter->writeCall($call); 500cecf9d5Sandi } 510cecf9d5Sandi 52533aca44SAndreas Gohr /** 53533aca44SAndreas Gohr * Accessor for the current CallWriter 54533aca44SAndreas Gohr * 55533aca44SAndreas Gohr * @return CallWriterInterface 56533aca44SAndreas Gohr */ 57533aca44SAndreas Gohr public function getCallWriter() { 58533aca44SAndreas Gohr return $this->callWriter; 59533aca44SAndreas Gohr } 60533aca44SAndreas Gohr 61533aca44SAndreas Gohr /** 62533aca44SAndreas Gohr * Set a new CallWriter 63533aca44SAndreas Gohr * 64533aca44SAndreas Gohr * @param CallWriterInterface $callWriter 65533aca44SAndreas Gohr */ 66533aca44SAndreas Gohr public function setCallWriter($callWriter) { 67533aca44SAndreas Gohr $this->callWriter = $callWriter; 68533aca44SAndreas Gohr } 69533aca44SAndreas Gohr 70*eb33b670SAndreas Gohr /** 71*eb33b670SAndreas Gohr * Return the current internal status of the given name 72*eb33b670SAndreas Gohr * 73*eb33b670SAndreas Gohr * @param string $status 74*eb33b670SAndreas Gohr * @return mixed|null 75*eb33b670SAndreas Gohr */ 76*eb33b670SAndreas Gohr public function getStatus($status) { 77*eb33b670SAndreas Gohr if (!isset($this->status[$status])) return null; 78*eb33b670SAndreas Gohr return $this->status[$status]; 79*eb33b670SAndreas Gohr } 80*eb33b670SAndreas Gohr 81*eb33b670SAndreas Gohr /** 82*eb33b670SAndreas Gohr * Set a new internal status 83*eb33b670SAndreas Gohr * 84*eb33b670SAndreas Gohr * @param string $status 85*eb33b670SAndreas Gohr * @param mixed $value 86*eb33b670SAndreas Gohr */ 87*eb33b670SAndreas Gohr public function setStatus($status, $value) { 88*eb33b670SAndreas Gohr $this->status[$status] = $value; 89*eb33b670SAndreas Gohr } 90*eb33b670SAndreas Gohr 9131c0895aSAndreas Gohr /** @deprecated 2019-10-31 use addCall() instead */ 9231c0895aSAndreas Gohr public function _addCall($handler, $args, $pos) { 9331c0895aSAndreas Gohr dbg_deprecated('addCall'); 9431c0895aSAndreas Gohr $this->addCall($handler, $args, $pos); 9531c0895aSAndreas Gohr } 9631c0895aSAndreas Gohr 978b1b81beSAndreas Gohr /** 988b1b81beSAndreas Gohr * Similar to addCall, but adds a plugin call 998b1b81beSAndreas Gohr * 1008b1b81beSAndreas Gohr * @param string $plugin name of the plugin 1018b1b81beSAndreas Gohr * @param mixed $args arguments for this call 1028b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 1038b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 1048b1b81beSAndreas Gohr * @param string $match matched syntax 1058b1b81beSAndreas Gohr */ 106767b83f9SAndreas Gohr public function addPluginCall($plugin, $args, $state, $pos, $match) { 10782d61635Spierre.spring $call = array('plugin',array($plugin, $args, $state, $match), $pos); 1088b1b81beSAndreas Gohr $this->callWriter->writeCall($call); 10904ebd214Schris } 11004ebd214Schris 1118b1b81beSAndreas Gohr /** 1128b1b81beSAndreas Gohr * Finishes handling 1138b1b81beSAndreas Gohr * 1148b1b81beSAndreas Gohr * Called from the parser. Calls finalise() on the call writer, closes open 1158b1b81beSAndreas Gohr * sections, rewrites blocks and adds document_start and document_end calls. 1168b1b81beSAndreas Gohr * 1178b1b81beSAndreas Gohr * @triggers PARSER_HANDLER_DONE 1188b1b81beSAndreas Gohr */ 1198b1b81beSAndreas Gohr public function finalize(){ 1208b1b81beSAndreas Gohr $this->callWriter->finalise(); 121f4f02a0fSchris 122e1c10e4dSchris if ( $this->status['section'] ) { 123e1c10e4dSchris $last_call = end($this->calls); 124e1c10e4dSchris array_push($this->calls,array('section_close',array(), $last_call[2])); 1250cecf9d5Sandi } 1260cecf9d5Sandi 127b7c441b9SHarry Fuecks if ( $this->rewriteBlocks ) { 1285c2aad12SAndreas Gohr $B = new Block(); 1290cecf9d5Sandi $this->calls = $B->process($this->calls); 130b7c441b9SHarry Fuecks } 131e0ad864eSchris 132cbb44eabSAndreas Gohr Event::createAndTrigger('PARSER_HANDLER_DONE',$this); 1330cecf9d5Sandi 1340cecf9d5Sandi array_unshift($this->calls,array('document_start',array(),0)); 1350cecf9d5Sandi $last_call = end($this->calls); 1360cecf9d5Sandi array_push($this->calls,array('document_end',array(),$last_call[2])); 1370cecf9d5Sandi } 1380cecf9d5Sandi 1399e491c01SAndreas Gohr /** 1409e491c01SAndreas Gohr * fetch the current call and advance the pointer to the next one 1419e491c01SAndreas Gohr * 1428b1b81beSAndreas Gohr * @fixme seems to be unused? 1439e491c01SAndreas Gohr * @return bool|mixed 1449e491c01SAndreas Gohr */ 1458b1b81beSAndreas Gohr public function fetch() { 1469e491c01SAndreas Gohr $call = current($this->calls); 1479e491c01SAndreas Gohr if($call !== false) { 1489e491c01SAndreas Gohr next($this->calls); //advance the pointer 1499e491c01SAndreas Gohr return $call; 1500cecf9d5Sandi } 15144881bd0Shenning.noren return false; 1520cecf9d5Sandi } 153ee20e7d1Sandi 154ee20e7d1Sandi 155ee20e7d1Sandi /** 156e2d88156SLarsDW223 * Internal function for parsing highlight options. 157e2d88156SLarsDW223 * $options is parsed for key value pairs separated by commas. 158e2d88156SLarsDW223 * A value might also be missing in which case the value will simple 159e2d88156SLarsDW223 * be set to true. Commas in strings are ignored, e.g. option="4,56" 160e2d88156SLarsDW223 * will work as expected and will only create one entry. 161e2d88156SLarsDW223 * 16254f741e8SAndreas Gohr * @param string $options space separated list of key-value pairs, 163e2d88156SLarsDW223 * e.g. option1=123, option2="456" 164e2d88156SLarsDW223 * @return array|null Array of key-value pairs $array['key'] = 'value'; 165e2d88156SLarsDW223 * or null if no entries found 166e2d88156SLarsDW223 */ 167e2d88156SLarsDW223 protected function parse_highlight_options($options) { 168e2d88156SLarsDW223 $result = array(); 16954f741e8SAndreas Gohr preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER); 170e2d88156SLarsDW223 foreach ($matches as $match) { 171e2d88156SLarsDW223 $equal_sign = strpos($match [0], '='); 172e2d88156SLarsDW223 if ($equal_sign === false) { 17354f741e8SAndreas Gohr $key = trim($match[0]); 174e2d88156SLarsDW223 $result [$key] = 1; 175e2d88156SLarsDW223 } else { 176e2d88156SLarsDW223 $key = substr($match[0], 0, $equal_sign); 177e2d88156SLarsDW223 $value = substr($match[0], $equal_sign+1); 178e2d88156SLarsDW223 $value = trim($value, '"'); 179e2d88156SLarsDW223 if (strlen($value) > 0) { 180e2d88156SLarsDW223 $result [$key] = $value; 181e2d88156SLarsDW223 } else { 182e2d88156SLarsDW223 $result [$key] = 1; 183e2d88156SLarsDW223 } 184e2d88156SLarsDW223 } 185e2d88156SLarsDW223 } 186e2d88156SLarsDW223 187e2d88156SLarsDW223 // Check for supported options 188e2d88156SLarsDW223 $result = array_intersect_key( 189e2d88156SLarsDW223 $result, 190e2d88156SLarsDW223 array_flip(array( 191e2d88156SLarsDW223 'enable_line_numbers', 192e2d88156SLarsDW223 'start_line_numbers_at', 193e2d88156SLarsDW223 'highlight_lines_extra', 194e2d88156SLarsDW223 'enable_keyword_links') 195e2d88156SLarsDW223 ) 196e2d88156SLarsDW223 ); 197e2d88156SLarsDW223 198e2d88156SLarsDW223 // Sanitize values 199e2d88156SLarsDW223 if(isset($result['enable_line_numbers'])) { 20054f741e8SAndreas Gohr if($result['enable_line_numbers'] === 'false') { 20154f741e8SAndreas Gohr $result['enable_line_numbers'] = false; 20254f741e8SAndreas Gohr } 203e2d88156SLarsDW223 $result['enable_line_numbers'] = (bool) $result['enable_line_numbers']; 204e2d88156SLarsDW223 } 205e2d88156SLarsDW223 if(isset($result['highlight_lines_extra'])) { 206e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra'])); 207e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']); 208e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']); 209e2d88156SLarsDW223 } 210e2d88156SLarsDW223 if(isset($result['start_line_numbers_at'])) { 211e2d88156SLarsDW223 $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at']; 212e2d88156SLarsDW223 } 213e2d88156SLarsDW223 if(isset($result['enable_keyword_links'])) { 21454f741e8SAndreas Gohr if($result['enable_keyword_links'] === 'false') { 21554f741e8SAndreas Gohr $result['enable_keyword_links'] = false; 21654f741e8SAndreas Gohr } 21754f741e8SAndreas Gohr $result['enable_keyword_links'] = (bool) $result['enable_keyword_links']; 218e2d88156SLarsDW223 } 219e2d88156SLarsDW223 if (count($result) == 0) { 220e2d88156SLarsDW223 return null; 221e2d88156SLarsDW223 } 222e2d88156SLarsDW223 223e2d88156SLarsDW223 return $result; 224e2d88156SLarsDW223 } 225e2d88156SLarsDW223 2268b1b81beSAndreas Gohr /** 2278b1b81beSAndreas Gohr * Simplifies handling for the formatting tags which all behave the same 2288b1b81beSAndreas Gohr * 2298b1b81beSAndreas Gohr * @param string $match matched syntax 2308b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 2318b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 2328b1b81beSAndreas Gohr * @param string $name actual mode name 2338b1b81beSAndreas Gohr */ 2348b1b81beSAndreas Gohr protected function nestingTag($match, $state, $pos, $name) { 2358b1b81beSAndreas Gohr switch ( $state ) { 2368b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 2378b1b81beSAndreas Gohr $this->addCall($name.'_open', array(), $pos); 2388b1b81beSAndreas Gohr break; 2398b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 2408b1b81beSAndreas Gohr $this->addCall($name.'_close', array(), $pos); 2418b1b81beSAndreas Gohr break; 2428b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 2438b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 2448b1b81beSAndreas Gohr break; 2458b1b81beSAndreas Gohr } 2468b1b81beSAndreas Gohr } 2478b1b81beSAndreas Gohr 2488b1b81beSAndreas Gohr 2498b1b81beSAndreas Gohr /** 2508b1b81beSAndreas Gohr * The following methods define the handlers for the different Syntax modes 2518b1b81beSAndreas Gohr * 252be906b56SAndreas Gohr * The handlers are called from dokuwiki\Parsing\Lexer\Lexer\invokeParser() 2538b1b81beSAndreas Gohr * 2548b1b81beSAndreas Gohr * @todo it might make sense to move these into their own class or merge them with the 2558b1b81beSAndreas Gohr * ParserMode classes some time. 2568b1b81beSAndreas Gohr */ 2578b1b81beSAndreas Gohr // region mode handlers 2588b1b81beSAndreas Gohr 2598b1b81beSAndreas Gohr /** 2608b1b81beSAndreas Gohr * Special plugin handler 2618b1b81beSAndreas Gohr * 2628b1b81beSAndreas Gohr * This handler is called for all modes starting with 'plugin_'. 2638b1b81beSAndreas Gohr * An additional parameter with the plugin name is passed. The plugin's handle() 2648b1b81beSAndreas Gohr * method is called here 2658b1b81beSAndreas Gohr * 2668b1b81beSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 2678b1b81beSAndreas Gohr * 2688b1b81beSAndreas Gohr * @param string $match matched syntax 2698b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 2708b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 2718b1b81beSAndreas Gohr * @param string $pluginname name of the plugin 2728b1b81beSAndreas Gohr * @return bool mode handled? 2738b1b81beSAndreas Gohr */ 2748b1b81beSAndreas Gohr public function plugin($match, $state, $pos, $pluginname){ 2758b1b81beSAndreas Gohr $data = array($match); 276e1d9dcc8SAndreas Gohr /** @var SyntaxPlugin $plugin */ 2778b1b81beSAndreas Gohr $plugin = plugin_load('syntax',$pluginname); 2788b1b81beSAndreas Gohr if($plugin != null){ 2798b1b81beSAndreas Gohr $data = $plugin->handle($match, $state, $pos, $this); 2808b1b81beSAndreas Gohr } 2818b1b81beSAndreas Gohr if ($data !== false) { 2828b1b81beSAndreas Gohr $this->addPluginCall($pluginname,$data,$state,$pos,$match); 2838b1b81beSAndreas Gohr } 2848b1b81beSAndreas Gohr return true; 2858b1b81beSAndreas Gohr } 2868b1b81beSAndreas Gohr 2878b1b81beSAndreas Gohr /** 2888b1b81beSAndreas Gohr * @param string $match matched syntax 2898b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 2908b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 2918b1b81beSAndreas Gohr * @return bool mode handled? 2928b1b81beSAndreas Gohr */ 2938b1b81beSAndreas Gohr public function base($match, $state, $pos) { 2948b1b81beSAndreas Gohr switch ( $state ) { 2958b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 2968b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 2978b1b81beSAndreas Gohr return true; 2988b1b81beSAndreas Gohr break; 2998b1b81beSAndreas Gohr } 3008b1b81beSAndreas Gohr return false; 3018b1b81beSAndreas Gohr } 3028b1b81beSAndreas Gohr 3038b1b81beSAndreas Gohr /** 3048b1b81beSAndreas Gohr * @param string $match matched syntax 3058b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3068b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3078b1b81beSAndreas Gohr * @return bool mode handled? 3088b1b81beSAndreas Gohr */ 3098b1b81beSAndreas Gohr public function header($match, $state, $pos) { 3108b1b81beSAndreas Gohr // get level and title 3118b1b81beSAndreas Gohr $title = trim($match); 3128b1b81beSAndreas Gohr $level = 7 - strspn($title,'='); 3138b1b81beSAndreas Gohr if($level < 1) $level = 1; 3148b1b81beSAndreas Gohr $title = trim($title,'='); 3158b1b81beSAndreas Gohr $title = trim($title); 3168b1b81beSAndreas Gohr 3178b1b81beSAndreas Gohr if ($this->status['section']) $this->addCall('section_close', array(), $pos); 3188b1b81beSAndreas Gohr 3198b1b81beSAndreas Gohr $this->addCall('header', array($title, $level, $pos), $pos); 3208b1b81beSAndreas Gohr 3218b1b81beSAndreas Gohr $this->addCall('section_open', array($level), $pos); 3228b1b81beSAndreas Gohr $this->status['section'] = true; 3238b1b81beSAndreas Gohr return true; 3248b1b81beSAndreas Gohr } 3258b1b81beSAndreas Gohr 3268b1b81beSAndreas Gohr /** 3278b1b81beSAndreas Gohr * @param string $match matched syntax 3288b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3298b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3308b1b81beSAndreas Gohr * @return bool mode handled? 3318b1b81beSAndreas Gohr */ 3328b1b81beSAndreas Gohr public function notoc($match, $state, $pos) { 3338b1b81beSAndreas Gohr $this->addCall('notoc', array(), $pos); 3348b1b81beSAndreas Gohr return true; 3358b1b81beSAndreas Gohr } 3368b1b81beSAndreas Gohr 3378b1b81beSAndreas Gohr /** 3388b1b81beSAndreas Gohr * @param string $match matched syntax 3398b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3408b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3418b1b81beSAndreas Gohr * @return bool mode handled? 3428b1b81beSAndreas Gohr */ 3438b1b81beSAndreas Gohr public function nocache($match, $state, $pos) { 3448b1b81beSAndreas Gohr $this->addCall('nocache', array(), $pos); 3458b1b81beSAndreas Gohr return true; 3468b1b81beSAndreas Gohr } 3478b1b81beSAndreas Gohr 3488b1b81beSAndreas Gohr /** 3498b1b81beSAndreas Gohr * @param string $match matched syntax 3508b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3518b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3528b1b81beSAndreas Gohr * @return bool mode handled? 3538b1b81beSAndreas Gohr */ 3548b1b81beSAndreas Gohr public function linebreak($match, $state, $pos) { 3558b1b81beSAndreas Gohr $this->addCall('linebreak', array(), $pos); 3568b1b81beSAndreas Gohr return true; 3578b1b81beSAndreas Gohr } 3588b1b81beSAndreas Gohr 3598b1b81beSAndreas Gohr /** 3608b1b81beSAndreas Gohr * @param string $match matched syntax 3618b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3628b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3638b1b81beSAndreas Gohr * @return bool mode handled? 3648b1b81beSAndreas Gohr */ 3658b1b81beSAndreas Gohr public function eol($match, $state, $pos) { 3668b1b81beSAndreas Gohr $this->addCall('eol', array(), $pos); 3678b1b81beSAndreas Gohr return true; 3688b1b81beSAndreas Gohr } 3698b1b81beSAndreas Gohr 3708b1b81beSAndreas Gohr /** 3718b1b81beSAndreas Gohr * @param string $match matched syntax 3728b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3738b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3748b1b81beSAndreas Gohr * @return bool mode handled? 3758b1b81beSAndreas Gohr */ 3768b1b81beSAndreas Gohr public function hr($match, $state, $pos) { 3778b1b81beSAndreas Gohr $this->addCall('hr', array(), $pos); 3788b1b81beSAndreas Gohr return true; 3798b1b81beSAndreas Gohr } 3808b1b81beSAndreas Gohr 3818b1b81beSAndreas Gohr /** 3828b1b81beSAndreas Gohr * @param string $match matched syntax 3838b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3848b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3858b1b81beSAndreas Gohr * @return bool mode handled? 3868b1b81beSAndreas Gohr */ 3878b1b81beSAndreas Gohr public function strong($match, $state, $pos) { 3888b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'strong'); 3898b1b81beSAndreas Gohr return true; 3908b1b81beSAndreas Gohr } 3918b1b81beSAndreas Gohr 3928b1b81beSAndreas Gohr /** 3938b1b81beSAndreas Gohr * @param string $match matched syntax 3948b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 3958b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 3968b1b81beSAndreas Gohr * @return bool mode handled? 3978b1b81beSAndreas Gohr */ 3988b1b81beSAndreas Gohr public function emphasis($match, $state, $pos) { 3998b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'emphasis'); 4008b1b81beSAndreas Gohr return true; 4018b1b81beSAndreas Gohr } 4028b1b81beSAndreas Gohr 4038b1b81beSAndreas Gohr /** 4048b1b81beSAndreas Gohr * @param string $match matched syntax 4058b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4068b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4078b1b81beSAndreas Gohr * @return bool mode handled? 4088b1b81beSAndreas Gohr */ 4098b1b81beSAndreas Gohr public function underline($match, $state, $pos) { 4108b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'underline'); 4118b1b81beSAndreas Gohr return true; 4128b1b81beSAndreas Gohr } 4138b1b81beSAndreas Gohr 4148b1b81beSAndreas Gohr /** 4158b1b81beSAndreas Gohr * @param string $match matched syntax 4168b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4178b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4188b1b81beSAndreas Gohr * @return bool mode handled? 4198b1b81beSAndreas Gohr */ 4208b1b81beSAndreas Gohr public function monospace($match, $state, $pos) { 4218b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'monospace'); 4228b1b81beSAndreas Gohr return true; 4238b1b81beSAndreas Gohr } 4248b1b81beSAndreas Gohr 4258b1b81beSAndreas Gohr /** 4268b1b81beSAndreas Gohr * @param string $match matched syntax 4278b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4288b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4298b1b81beSAndreas Gohr * @return bool mode handled? 4308b1b81beSAndreas Gohr */ 4318b1b81beSAndreas Gohr public function subscript($match, $state, $pos) { 4328b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'subscript'); 4338b1b81beSAndreas Gohr return true; 4348b1b81beSAndreas Gohr } 4358b1b81beSAndreas Gohr 4368b1b81beSAndreas Gohr /** 4378b1b81beSAndreas Gohr * @param string $match matched syntax 4388b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4398b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4408b1b81beSAndreas Gohr * @return bool mode handled? 4418b1b81beSAndreas Gohr */ 4428b1b81beSAndreas Gohr public function superscript($match, $state, $pos) { 4438b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'superscript'); 4448b1b81beSAndreas Gohr return true; 4458b1b81beSAndreas Gohr } 4468b1b81beSAndreas Gohr 4478b1b81beSAndreas Gohr /** 4488b1b81beSAndreas Gohr * @param string $match matched syntax 4498b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4508b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4518b1b81beSAndreas Gohr * @return bool mode handled? 4528b1b81beSAndreas Gohr */ 4538b1b81beSAndreas Gohr public function deleted($match, $state, $pos) { 4548b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'deleted'); 4558b1b81beSAndreas Gohr return true; 4568b1b81beSAndreas Gohr } 4578b1b81beSAndreas Gohr 4588b1b81beSAndreas Gohr /** 4598b1b81beSAndreas Gohr * @param string $match matched syntax 4608b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 4618b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 4628b1b81beSAndreas Gohr * @return bool mode handled? 4638b1b81beSAndreas Gohr */ 4648b1b81beSAndreas Gohr public function footnote($match, $state, $pos) { 4658b1b81beSAndreas Gohr if (!isset($this->_footnote)) $this->_footnote = false; 4668b1b81beSAndreas Gohr 4678b1b81beSAndreas Gohr switch ( $state ) { 4688b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 4698b1b81beSAndreas Gohr // footnotes can not be nested - however due to limitations in lexer it can't be prevented 4708b1b81beSAndreas Gohr // we will still enter a new footnote mode, we just do nothing 4718b1b81beSAndreas Gohr if ($this->_footnote) { 4728b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 4738b1b81beSAndreas Gohr break; 4748b1b81beSAndreas Gohr } 4758b1b81beSAndreas Gohr $this->_footnote = true; 4768b1b81beSAndreas Gohr 4778b1b81beSAndreas Gohr $this->callWriter = new Nest($this->callWriter, 'footnote_close'); 4788b1b81beSAndreas Gohr $this->addCall('footnote_open', array(), $pos); 4798b1b81beSAndreas Gohr break; 4808b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 4818b1b81beSAndreas Gohr // check whether we have already exitted the footnote mode, can happen if the modes were nested 4828b1b81beSAndreas Gohr if (!$this->_footnote) { 4838b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 4848b1b81beSAndreas Gohr break; 4858b1b81beSAndreas Gohr } 4868b1b81beSAndreas Gohr 4878b1b81beSAndreas Gohr $this->_footnote = false; 4888b1b81beSAndreas Gohr $this->addCall('footnote_close', array(), $pos); 4898b1b81beSAndreas Gohr 4908b1b81beSAndreas Gohr /** @var Nest $reWriter */ 4918b1b81beSAndreas Gohr $reWriter = $this->callWriter; 4928b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 4938b1b81beSAndreas Gohr break; 4948b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 4958b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 4968b1b81beSAndreas Gohr break; 4978b1b81beSAndreas Gohr } 4988b1b81beSAndreas Gohr return true; 4998b1b81beSAndreas Gohr } 5008b1b81beSAndreas Gohr 5018b1b81beSAndreas Gohr /** 5028b1b81beSAndreas Gohr * @param string $match matched syntax 5038b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5048b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5058b1b81beSAndreas Gohr * @return bool mode handled? 5068b1b81beSAndreas Gohr */ 5078b1b81beSAndreas Gohr public function listblock($match, $state, $pos) { 5088b1b81beSAndreas Gohr switch ( $state ) { 5098b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 5108b1b81beSAndreas Gohr $this->callWriter = new Lists($this->callWriter); 5118b1b81beSAndreas Gohr $this->addCall('list_open', array($match), $pos); 5128b1b81beSAndreas Gohr break; 5138b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 5148b1b81beSAndreas Gohr $this->addCall('list_close', array(), $pos); 5158b1b81beSAndreas Gohr /** @var Lists $reWriter */ 5168b1b81beSAndreas Gohr $reWriter = $this->callWriter; 5178b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 5188b1b81beSAndreas Gohr break; 5198b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 5208b1b81beSAndreas Gohr $this->addCall('list_item', array($match), $pos); 5218b1b81beSAndreas Gohr break; 5228b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 5238b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 5248b1b81beSAndreas Gohr break; 5258b1b81beSAndreas Gohr } 5268b1b81beSAndreas Gohr return true; 5278b1b81beSAndreas Gohr } 5288b1b81beSAndreas Gohr 5298b1b81beSAndreas Gohr /** 5308b1b81beSAndreas Gohr * @param string $match matched syntax 5318b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5328b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5338b1b81beSAndreas Gohr * @return bool mode handled? 5348b1b81beSAndreas Gohr */ 5358b1b81beSAndreas Gohr public function unformatted($match, $state, $pos) { 5368b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 5378b1b81beSAndreas Gohr $this->addCall('unformatted', array($match), $pos); 5388b1b81beSAndreas Gohr } 5398b1b81beSAndreas Gohr return true; 5408b1b81beSAndreas Gohr } 5418b1b81beSAndreas Gohr 5428b1b81beSAndreas Gohr /** 5438b1b81beSAndreas Gohr * @param string $match matched syntax 5448b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5458b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5468b1b81beSAndreas Gohr * @return bool mode handled? 5478b1b81beSAndreas Gohr */ 5488b1b81beSAndreas Gohr public function php($match, $state, $pos) { 5498b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 5508b1b81beSAndreas Gohr $this->addCall('php', array($match), $pos); 5518b1b81beSAndreas Gohr } 5528b1b81beSAndreas Gohr return true; 5538b1b81beSAndreas Gohr } 5548b1b81beSAndreas Gohr 5558b1b81beSAndreas Gohr /** 5568b1b81beSAndreas Gohr * @param string $match matched syntax 5578b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5588b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5598b1b81beSAndreas Gohr * @return bool mode handled? 5608b1b81beSAndreas Gohr */ 5618b1b81beSAndreas Gohr public function phpblock($match, $state, $pos) { 5628b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 5638b1b81beSAndreas Gohr $this->addCall('phpblock', array($match), $pos); 5648b1b81beSAndreas Gohr } 5658b1b81beSAndreas Gohr return true; 5668b1b81beSAndreas Gohr } 5678b1b81beSAndreas Gohr 5688b1b81beSAndreas Gohr /** 5698b1b81beSAndreas Gohr * @param string $match matched syntax 5708b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5718b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5728b1b81beSAndreas Gohr * @return bool mode handled? 5738b1b81beSAndreas Gohr */ 5748b1b81beSAndreas Gohr public function html($match, $state, $pos) { 5758b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 5768b1b81beSAndreas Gohr $this->addCall('html', array($match), $pos); 5778b1b81beSAndreas Gohr } 5788b1b81beSAndreas Gohr return true; 5798b1b81beSAndreas Gohr } 5808b1b81beSAndreas Gohr 5818b1b81beSAndreas Gohr /** 5828b1b81beSAndreas Gohr * @param string $match matched syntax 5838b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5848b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5858b1b81beSAndreas Gohr * @return bool mode handled? 5868b1b81beSAndreas Gohr */ 5878b1b81beSAndreas Gohr public function htmlblock($match, $state, $pos) { 5888b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 5898b1b81beSAndreas Gohr $this->addCall('htmlblock', array($match), $pos); 5908b1b81beSAndreas Gohr } 5918b1b81beSAndreas Gohr return true; 5928b1b81beSAndreas Gohr } 5938b1b81beSAndreas Gohr 5948b1b81beSAndreas Gohr /** 5958b1b81beSAndreas Gohr * @param string $match matched syntax 5968b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 5978b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 5988b1b81beSAndreas Gohr * @return bool mode handled? 5998b1b81beSAndreas Gohr */ 6008b1b81beSAndreas Gohr public function preformatted($match, $state, $pos) { 6018b1b81beSAndreas Gohr switch ( $state ) { 6028b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 6038b1b81beSAndreas Gohr $this->callWriter = new Preformatted($this->callWriter); 6048b1b81beSAndreas Gohr $this->addCall('preformatted_start', array(), $pos); 6058b1b81beSAndreas Gohr break; 6068b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 6078b1b81beSAndreas Gohr $this->addCall('preformatted_end', array(), $pos); 6088b1b81beSAndreas Gohr /** @var Preformatted $reWriter */ 6098b1b81beSAndreas Gohr $reWriter = $this->callWriter; 6108b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 6118b1b81beSAndreas Gohr break; 6128b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 6138b1b81beSAndreas Gohr $this->addCall('preformatted_newline', array(), $pos); 6148b1b81beSAndreas Gohr break; 6158b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 6168b1b81beSAndreas Gohr $this->addCall('preformatted_content', array($match), $pos); 6178b1b81beSAndreas Gohr break; 6188b1b81beSAndreas Gohr } 6198b1b81beSAndreas Gohr 6208b1b81beSAndreas Gohr return true; 6218b1b81beSAndreas Gohr } 6228b1b81beSAndreas Gohr 6238b1b81beSAndreas Gohr /** 6248b1b81beSAndreas Gohr * @param string $match matched syntax 6258b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 6268b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 6278b1b81beSAndreas Gohr * @return bool mode handled? 6288b1b81beSAndreas Gohr */ 6298b1b81beSAndreas Gohr public function quote($match, $state, $pos) { 6308b1b81beSAndreas Gohr 6318b1b81beSAndreas Gohr switch ( $state ) { 6328b1b81beSAndreas Gohr 6338b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 6348b1b81beSAndreas Gohr $this->callWriter = new Quote($this->callWriter); 6358b1b81beSAndreas Gohr $this->addCall('quote_start', array($match), $pos); 6368b1b81beSAndreas Gohr break; 6378b1b81beSAndreas Gohr 6388b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 6398b1b81beSAndreas Gohr $this->addCall('quote_end', array(), $pos); 6408b1b81beSAndreas Gohr /** @var Lists $reWriter */ 6418b1b81beSAndreas Gohr $reWriter = $this->callWriter; 6428b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 6438b1b81beSAndreas Gohr break; 6448b1b81beSAndreas Gohr 6458b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 6468b1b81beSAndreas Gohr $this->addCall('quote_newline', array($match), $pos); 6478b1b81beSAndreas Gohr break; 6488b1b81beSAndreas Gohr 6498b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 6508b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 6518b1b81beSAndreas Gohr break; 6528b1b81beSAndreas Gohr 6538b1b81beSAndreas Gohr } 6548b1b81beSAndreas Gohr 6558b1b81beSAndreas Gohr return true; 6568b1b81beSAndreas Gohr } 6578b1b81beSAndreas Gohr 6588b1b81beSAndreas Gohr /** 6598b1b81beSAndreas Gohr * @param string $match matched syntax 6608b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 6618b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 6628b1b81beSAndreas Gohr * @return bool mode handled? 6638b1b81beSAndreas Gohr */ 6648b1b81beSAndreas Gohr public function file($match, $state, $pos) { 6653d491f75SAndreas Gohr return $this->code($match, $state, $pos, 'file'); 6663d491f75SAndreas Gohr } 6673d491f75SAndreas Gohr 6688b1b81beSAndreas Gohr /** 6698b1b81beSAndreas Gohr * @param string $match matched syntax 6708b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 6718b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 6728b1b81beSAndreas Gohr * @param string $type either 'code' or 'file' 6738b1b81beSAndreas Gohr * @return bool mode handled? 6748b1b81beSAndreas Gohr */ 6758b1b81beSAndreas Gohr public function code($match, $state, $pos, $type='code') { 6763d491f75SAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 6774b7f9e70STom N Harris $matches = explode('>',$match,2); 678e2d88156SLarsDW223 // Cut out variable options enclosed in [] 679e2d88156SLarsDW223 preg_match('/\[.*\]/', $matches[0], $options); 680e2d88156SLarsDW223 if (!empty($options[0])) { 681e2d88156SLarsDW223 $matches[0] = str_replace($options[0], '', $matches[0]); 682e2d88156SLarsDW223 } 6830139312bSAdrian Lang $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY); 6840139312bSAdrian Lang while(count($param) < 2) array_push($param, null); 6850139312bSAdrian Lang // We shortcut html here. 6860139312bSAdrian Lang if ($param[0] == 'html') $param[0] = 'html4strict'; 6870139312bSAdrian Lang if ($param[0] == '-') $param[0] = null; 6880139312bSAdrian Lang array_unshift($param, $matches[1]); 689e2d88156SLarsDW223 if (!empty($options[0])) { 690e2d88156SLarsDW223 $param [] = $this->parse_highlight_options ($options[0]); 691e2d88156SLarsDW223 } 6928b1b81beSAndreas Gohr $this->addCall($type, $param, $pos); 6930cecf9d5Sandi } 69444881bd0Shenning.noren return true; 6950cecf9d5Sandi } 6960cecf9d5Sandi 6978b1b81beSAndreas Gohr /** 6988b1b81beSAndreas Gohr * @param string $match matched syntax 6998b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7008b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7018b1b81beSAndreas Gohr * @return bool mode handled? 7028b1b81beSAndreas Gohr */ 7038b1b81beSAndreas Gohr public function acronym($match, $state, $pos) { 7048b1b81beSAndreas Gohr $this->addCall('acronym', array($match), $pos); 70544881bd0Shenning.noren return true; 7060cecf9d5Sandi } 7070cecf9d5Sandi 7088b1b81beSAndreas Gohr /** 7098b1b81beSAndreas Gohr * @param string $match matched syntax 7108b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7118b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7128b1b81beSAndreas Gohr * @return bool mode handled? 7138b1b81beSAndreas Gohr */ 7148b1b81beSAndreas Gohr public function smiley($match, $state, $pos) { 7158b1b81beSAndreas Gohr $this->addCall('smiley', array($match), $pos); 71644881bd0Shenning.noren return true; 7170cecf9d5Sandi } 7180cecf9d5Sandi 7198b1b81beSAndreas Gohr /** 7208b1b81beSAndreas Gohr * @param string $match matched syntax 7218b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7228b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7238b1b81beSAndreas Gohr * @return bool mode handled? 7248b1b81beSAndreas Gohr */ 7258b1b81beSAndreas Gohr public function wordblock($match, $state, $pos) { 7268b1b81beSAndreas Gohr $this->addCall('wordblock', array($match), $pos); 72744881bd0Shenning.noren return true; 7280cecf9d5Sandi } 7290cecf9d5Sandi 7308b1b81beSAndreas Gohr /** 7318b1b81beSAndreas Gohr * @param string $match matched syntax 7328b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7338b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7348b1b81beSAndreas Gohr * @return bool mode handled? 7358b1b81beSAndreas Gohr */ 7368b1b81beSAndreas Gohr public function entity($match, $state, $pos) { 7378b1b81beSAndreas Gohr $this->addCall('entity', array($match), $pos); 73844881bd0Shenning.noren return true; 7390cecf9d5Sandi } 7400cecf9d5Sandi 7418b1b81beSAndreas Gohr /** 7428b1b81beSAndreas Gohr * @param string $match matched syntax 7438b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7448b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7458b1b81beSAndreas Gohr * @return bool mode handled? 7468b1b81beSAndreas Gohr */ 7478b1b81beSAndreas Gohr public function multiplyentity($match, $state, $pos) { 7480cecf9d5Sandi preg_match_all('/\d+/',$match,$matches); 7498b1b81beSAndreas Gohr $this->addCall('multiplyentity', array($matches[0][0], $matches[0][1]), $pos); 75044881bd0Shenning.noren return true; 7510cecf9d5Sandi } 7520cecf9d5Sandi 7538b1b81beSAndreas Gohr /** 7548b1b81beSAndreas Gohr * @param string $match matched syntax 7558b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7568b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7578b1b81beSAndreas Gohr * @return bool mode handled? 7588b1b81beSAndreas Gohr */ 7598b1b81beSAndreas Gohr public function singlequoteopening($match, $state, $pos) { 7608b1b81beSAndreas Gohr $this->addCall('singlequoteopening', array(), $pos); 76144881bd0Shenning.noren return true; 7620cecf9d5Sandi } 7630cecf9d5Sandi 7648b1b81beSAndreas Gohr /** 7658b1b81beSAndreas Gohr * @param string $match matched syntax 7668b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7678b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7688b1b81beSAndreas Gohr * @return bool mode handled? 7698b1b81beSAndreas Gohr */ 7708b1b81beSAndreas Gohr public function singlequoteclosing($match, $state, $pos) { 7718b1b81beSAndreas Gohr $this->addCall('singlequoteclosing', array(), $pos); 77244881bd0Shenning.noren return true; 7730cecf9d5Sandi } 7740cecf9d5Sandi 7758b1b81beSAndreas Gohr /** 7768b1b81beSAndreas Gohr * @param string $match matched syntax 7778b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7788b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7798b1b81beSAndreas Gohr * @return bool mode handled? 7808b1b81beSAndreas Gohr */ 7818b1b81beSAndreas Gohr public function apostrophe($match, $state, $pos) { 7828b1b81beSAndreas Gohr $this->addCall('apostrophe', array(), $pos); 78357d757d1SAndreas Gohr return true; 78457d757d1SAndreas Gohr } 78557d757d1SAndreas Gohr 7868b1b81beSAndreas Gohr /** 7878b1b81beSAndreas Gohr * @param string $match matched syntax 7888b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 7898b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 7908b1b81beSAndreas Gohr * @return bool mode handled? 7918b1b81beSAndreas Gohr */ 7928b1b81beSAndreas Gohr public function doublequoteopening($match, $state, $pos) { 7938b1b81beSAndreas Gohr $this->addCall('doublequoteopening', array(), $pos); 794e950d12fSChristopher Smith $this->status['doublequote']++; 79544881bd0Shenning.noren return true; 7960cecf9d5Sandi } 7970cecf9d5Sandi 7988b1b81beSAndreas Gohr /** 7998b1b81beSAndreas Gohr * @param string $match matched syntax 8008b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 8018b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 8028b1b81beSAndreas Gohr * @return bool mode handled? 8038b1b81beSAndreas Gohr */ 8048b1b81beSAndreas Gohr public function doublequoteclosing($match, $state, $pos) { 805e950d12fSChristopher Smith if ($this->status['doublequote'] <= 0) { 806e950d12fSChristopher Smith $this->doublequoteopening($match, $state, $pos); 807e950d12fSChristopher Smith } else { 8088b1b81beSAndreas Gohr $this->addCall('doublequoteclosing', array(), $pos); 809e950d12fSChristopher Smith $this->status['doublequote'] = max(0, --$this->status['doublequote']); 810e950d12fSChristopher Smith } 81144881bd0Shenning.noren return true; 8120cecf9d5Sandi } 8130cecf9d5Sandi 8148b1b81beSAndreas Gohr /** 8158b1b81beSAndreas Gohr * @param string $match matched syntax 8168b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 8178b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 8188b1b81beSAndreas Gohr * @return bool mode handled? 8198b1b81beSAndreas Gohr */ 8208b1b81beSAndreas Gohr public function camelcaselink($match, $state, $pos) { 8218b1b81beSAndreas Gohr $this->addCall('camelcaselink', array($match), $pos); 82244881bd0Shenning.noren return true; 8230cecf9d5Sandi } 8240cecf9d5Sandi 8258b1b81beSAndreas Gohr /** 8268b1b81beSAndreas Gohr * @param string $match matched syntax 8278b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 8288b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 8298b1b81beSAndreas Gohr * @return bool mode handled? 8300cecf9d5Sandi */ 8318b1b81beSAndreas Gohr public function internallink($match, $state, $pos) { 8320cecf9d5Sandi // Strip the opening and closing markup 8330cecf9d5Sandi $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); 8340cecf9d5Sandi 8350cecf9d5Sandi // Split title from URL 8364b7f9e70STom N Harris $link = explode('|',$link,2); 8370cecf9d5Sandi if ( !isset($link[1]) ) { 8380ea51e63SMatt Perry $link[1] = null; 8390cecf9d5Sandi } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) { 8405578eb8fSandi // If the title is an image, convert it to an array containing the image details 841b625487dSandi $link[1] = Doku_Handler_Parse_Media($link[1]); 8420cecf9d5Sandi } 8430b7c14c2Sandi $link[0] = trim($link[0]); 8440cecf9d5Sandi 8450e1c636eSandi //decide which kind of link it is 8460e1c636eSandi 8476efc45a2SDmitry Katsubo if ( link_isinterwiki($link[0]) ) { 8480e1c636eSandi // Interwiki 8494b7f9e70STom N Harris $interwiki = explode('>',$link[0],2); 8508b1b81beSAndreas Gohr $this->addCall( 8510cecf9d5Sandi 'interwikilink', 8520cecf9d5Sandi array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), 8530cecf9d5Sandi $pos 8540cecf9d5Sandi ); 85515f1b77cSAndreas Gohr }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { 8560e1c636eSandi // Windows Share 8578b1b81beSAndreas Gohr $this->addCall( 8580cecf9d5Sandi 'windowssharelink', 8590cecf9d5Sandi array($link[0],$link[1]), 8600cecf9d5Sandi $pos 8610cecf9d5Sandi ); 8624468cb4cSAndreas Gohr }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) { 8630e1c636eSandi // external link (accepts all protocols) 8648b1b81beSAndreas Gohr $this->addCall( 8650cecf9d5Sandi 'externallink', 8660cecf9d5Sandi array($link[0],$link[1]), 8670cecf9d5Sandi $pos 8680cecf9d5Sandi ); 8690a1d30bfSchris }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) { 8700a1d30bfSchris // E-Mail (pattern above is defined in inc/mail.php) 8718b1b81beSAndreas Gohr $this->addCall( 872a6755281Sandi 'emaillink', 873a6755281Sandi array($link[0],$link[1]), 874a6755281Sandi $pos 875a6755281Sandi ); 8760b7c14c2Sandi }elseif ( preg_match('!^#.+!',$link[0]) ){ 8770b7c14c2Sandi // local link 8788b1b81beSAndreas Gohr $this->addCall( 8790b7c14c2Sandi 'locallink', 8800b7c14c2Sandi array(substr($link[0],1),$link[1]), 8810b7c14c2Sandi $pos 8820b7c14c2Sandi ); 8830e1c636eSandi }else{ 8840e1c636eSandi // internal link 8858b1b81beSAndreas Gohr $this->addCall( 8860e1c636eSandi 'internallink', 8870e1c636eSandi array($link[0],$link[1]), 8880e1c636eSandi $pos 8890e1c636eSandi ); 8900cecf9d5Sandi } 8910e1c636eSandi 89244881bd0Shenning.noren return true; 8930cecf9d5Sandi } 8940cecf9d5Sandi 8958b1b81beSAndreas Gohr /** 8968b1b81beSAndreas Gohr * @param string $match matched syntax 8978b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 8988b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 8998b1b81beSAndreas Gohr * @return bool mode handled? 9008b1b81beSAndreas Gohr */ 9018b1b81beSAndreas Gohr public function filelink($match, $state, $pos) { 9028b1b81beSAndreas Gohr $this->addCall('filelink', array($match, null), $pos); 90344881bd0Shenning.noren return true; 9040cecf9d5Sandi } 9050cecf9d5Sandi 9068b1b81beSAndreas Gohr /** 9078b1b81beSAndreas Gohr * @param string $match matched syntax 9088b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 9098b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 9108b1b81beSAndreas Gohr * @return bool mode handled? 9118b1b81beSAndreas Gohr */ 9128b1b81beSAndreas Gohr public function windowssharelink($match, $state, $pos) { 9138b1b81beSAndreas Gohr $this->addCall('windowssharelink', array($match, null), $pos); 91444881bd0Shenning.noren return true; 9150cecf9d5Sandi } 9160cecf9d5Sandi 9178b1b81beSAndreas Gohr /** 9188b1b81beSAndreas Gohr * @param string $match matched syntax 9198b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 9208b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 9218b1b81beSAndreas Gohr * @return bool mode handled? 9228b1b81beSAndreas Gohr */ 9238b1b81beSAndreas Gohr public function media($match, $state, $pos) { 9240cecf9d5Sandi $p = Doku_Handler_Parse_Media($match); 9250cecf9d5Sandi 9268b1b81beSAndreas Gohr $this->addCall( 9270cecf9d5Sandi $p['type'], 928dc673a5bSjoe.lapp array($p['src'], $p['title'], $p['align'], $p['width'], 929dc673a5bSjoe.lapp $p['height'], $p['cache'], $p['linking']), 9300cecf9d5Sandi $pos 9310cecf9d5Sandi ); 93244881bd0Shenning.noren return true; 9330cecf9d5Sandi } 9340cecf9d5Sandi 9358b1b81beSAndreas Gohr /** 9368b1b81beSAndreas Gohr * @param string $match matched syntax 9378b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 9388b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 9398b1b81beSAndreas Gohr * @return bool mode handled? 9408b1b81beSAndreas Gohr */ 9418b1b81beSAndreas Gohr public function rss($match, $state, $pos) { 942b625487dSandi $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); 9433db95becSAndreas Gohr 9443db95becSAndreas Gohr // get params 9453db95becSAndreas Gohr list($link,$params) = explode(' ',$link,2); 9463db95becSAndreas Gohr 9473db95becSAndreas Gohr $p = array(); 9483db95becSAndreas Gohr if(preg_match('/\b(\d+)\b/',$params,$match)){ 9493db95becSAndreas Gohr $p['max'] = $match[1]; 9503db95becSAndreas Gohr }else{ 9513db95becSAndreas Gohr $p['max'] = 8; 9523db95becSAndreas Gohr } 9533db95becSAndreas Gohr $p['reverse'] = (preg_match('/rev/',$params)); 9543db95becSAndreas Gohr $p['author'] = (preg_match('/\b(by|author)/',$params)); 9553db95becSAndreas Gohr $p['date'] = (preg_match('/\b(date)/',$params)); 9563db95becSAndreas Gohr $p['details'] = (preg_match('/\b(desc|detail)/',$params)); 95738c6f603SRobin H. Johnson $p['nosort'] = (preg_match('/\b(nosort)\b/',$params)); 9583db95becSAndreas Gohr 9590a69dff7Schris if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) { 9600a69dff7Schris $period = array('d' => 86400, 'h' => 3600, 'm' => 60); 9610a69dff7Schris $p['refresh'] = max(600,$match[1]*$period[$match[2]]); // n * period in seconds, minimum 10 minutes 9620a69dff7Schris } else { 9630a69dff7Schris $p['refresh'] = 14400; // default to 4 hours 9640a69dff7Schris } 9650a69dff7Schris 9668b1b81beSAndreas Gohr $this->addCall('rss', array($link, $p), $pos); 96744881bd0Shenning.noren return true; 968b625487dSandi } 969b625487dSandi 9708b1b81beSAndreas Gohr /** 9718b1b81beSAndreas Gohr * @param string $match matched syntax 9728b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 9738b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 9748b1b81beSAndreas Gohr * @return bool mode handled? 9758b1b81beSAndreas Gohr */ 9768b1b81beSAndreas Gohr public function externallink($match, $state, $pos) { 977da9f31c5SAndreas Gohr $url = $match; 978da9f31c5SAndreas Gohr $title = null; 9790cecf9d5Sandi 980da9f31c5SAndreas Gohr // add protocol on simple short URLs 981da9f31c5SAndreas Gohr if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){ 982da9f31c5SAndreas Gohr $title = $url; 983da9f31c5SAndreas Gohr $url = 'ftp://'.$url; 984da9f31c5SAndreas Gohr } 985da9f31c5SAndreas Gohr if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){ 986da9f31c5SAndreas Gohr $title = $url; 987da9f31c5SAndreas Gohr $url = 'http://'.$url; 988da9f31c5SAndreas Gohr } 989da9f31c5SAndreas Gohr 9908b1b81beSAndreas Gohr $this->addCall('externallink', array($url, $title), $pos); 99144881bd0Shenning.noren return true; 9920cecf9d5Sandi } 9930cecf9d5Sandi 9948b1b81beSAndreas Gohr /** 9958b1b81beSAndreas Gohr * @param string $match matched syntax 9968b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 9978b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 9988b1b81beSAndreas Gohr * @return bool mode handled? 9998b1b81beSAndreas Gohr */ 10008b1b81beSAndreas Gohr public function emaillink($match, $state, $pos) { 10010cecf9d5Sandi $email = preg_replace(array('/^</','/>$/'),'',$match); 10028b1b81beSAndreas Gohr $this->addCall('emaillink', array($email, null), $pos); 100344881bd0Shenning.noren return true; 10040cecf9d5Sandi } 10050cecf9d5Sandi 10068b1b81beSAndreas Gohr /** 10078b1b81beSAndreas Gohr * @param string $match matched syntax 10088b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 10098b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 10108b1b81beSAndreas Gohr * @return bool mode handled? 10118b1b81beSAndreas Gohr */ 10128b1b81beSAndreas Gohr public function table($match, $state, $pos) { 10130cecf9d5Sandi switch ( $state ) { 10140cecf9d5Sandi 10150cecf9d5Sandi case DOKU_LEXER_ENTER: 10160cecf9d5Sandi 10178b1b81beSAndreas Gohr $this->callWriter = new Table($this->callWriter); 10180cecf9d5Sandi 10198b1b81beSAndreas Gohr $this->addCall('table_start', array($pos + 1), $pos); 10200cecf9d5Sandi if ( trim($match) == '^' ) { 10218b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 10220cecf9d5Sandi } else { 10238b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 10240cecf9d5Sandi } 10250cecf9d5Sandi break; 10260cecf9d5Sandi 10270cecf9d5Sandi case DOKU_LEXER_EXIT: 10288b1b81beSAndreas Gohr $this->addCall('table_end', array($pos), $pos); 10295c2aad12SAndreas Gohr /** @var Table $reWriter */ 10308b1b81beSAndreas Gohr $reWriter = $this->callWriter; 10318b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 10320cecf9d5Sandi break; 10330cecf9d5Sandi 10340cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 10350cecf9d5Sandi if ( trim($match) != '' ) { 10368b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 10370cecf9d5Sandi } 10380cecf9d5Sandi break; 10390cecf9d5Sandi 10400cecf9d5Sandi case DOKU_LEXER_MATCHED: 10419ab75d9eSAndreas Gohr if ( $match == ' ' ){ 10428b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 104325b97867Shakan.sandell } else if ( preg_match('/:::/',$match) ) { 10448b1b81beSAndreas Gohr $this->addCall('rowspan', array($match), $pos); 1045e205b721SAndreas Gohr } else if ( preg_match('/\t+/',$match) ) { 10468b1b81beSAndreas Gohr $this->addCall('table_align', array($match), $pos); 1047e205b721SAndreas Gohr } else if ( preg_match('/ {2,}/',$match) ) { 10488b1b81beSAndreas Gohr $this->addCall('table_align', array($match), $pos); 10490cecf9d5Sandi } else if ( $match == "\n|" ) { 10508b1b81beSAndreas Gohr $this->addCall('table_row', array(), $pos); 10518b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 10520cecf9d5Sandi } else if ( $match == "\n^" ) { 10538b1b81beSAndreas Gohr $this->addCall('table_row', array(), $pos); 10548b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 10550cecf9d5Sandi } else if ( $match == '|' ) { 10568b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 10570cecf9d5Sandi } else if ( $match == '^' ) { 10588b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 10590cecf9d5Sandi } 10600cecf9d5Sandi break; 10610cecf9d5Sandi } 106244881bd0Shenning.noren return true; 10630cecf9d5Sandi } 10648b1b81beSAndreas Gohr 10658b1b81beSAndreas Gohr // endregion modes 10660cecf9d5Sandi} 10670cecf9d5Sandi 10680cecf9d5Sandi//------------------------------------------------------------------------ 10690cecf9d5Sandifunction Doku_Handler_Parse_Media($match) { 10700cecf9d5Sandi 10710cecf9d5Sandi // Strip the opening and closing markup 10720cecf9d5Sandi $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); 10730cecf9d5Sandi 10740cecf9d5Sandi // Split title from URL 10754b7f9e70STom N Harris $link = explode('|',$link,2); 10760cecf9d5Sandi 10770cecf9d5Sandi // Check alignment 10780cecf9d5Sandi $ralign = (bool)preg_match('/^ /',$link[0]); 10790cecf9d5Sandi $lalign = (bool)preg_match('/ $/',$link[0]); 10800cecf9d5Sandi 10810cecf9d5Sandi // Logic = what's that ;)... 10820cecf9d5Sandi if ( $lalign & $ralign ) { 10830cecf9d5Sandi $align = 'center'; 10840cecf9d5Sandi } else if ( $ralign ) { 10850cecf9d5Sandi $align = 'right'; 10860cecf9d5Sandi } else if ( $lalign ) { 10870cecf9d5Sandi $align = 'left'; 10880cecf9d5Sandi } else { 10890ea51e63SMatt Perry $align = null; 10900cecf9d5Sandi } 10910cecf9d5Sandi 10920cecf9d5Sandi // The title... 10930cecf9d5Sandi if ( !isset($link[1]) ) { 10940ea51e63SMatt Perry $link[1] = null; 10950cecf9d5Sandi } 10960cecf9d5Sandi 10974826ab45Sandi //remove aligning spaces 10984826ab45Sandi $link[0] = trim($link[0]); 10990cecf9d5Sandi 11004826ab45Sandi //split into src and parameters (using the very last questionmark) 11014826ab45Sandi $pos = strrpos($link[0], '?'); 11024826ab45Sandi if($pos !== false){ 11034826ab45Sandi $src = substr($link[0],0,$pos); 11044826ab45Sandi $param = substr($link[0],$pos+1); 11050cecf9d5Sandi }else{ 11064826ab45Sandi $src = $link[0]; 11074826ab45Sandi $param = ''; 11080cecf9d5Sandi } 11090cecf9d5Sandi 11104826ab45Sandi //parse width and height 11114826ab45Sandi if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){ 1112443e135dSChristopher Smith !empty($size[1]) ? $w = $size[1] : $w = null; 1113443e135dSChristopher Smith !empty($size[3]) ? $h = $size[3] : $h = null; 1114fc1c55b1Shfuecks } else { 11150ea51e63SMatt Perry $w = null; 11160ea51e63SMatt Perry $h = null; 11170cecf9d5Sandi } 11180cecf9d5Sandi 1119dc673a5bSjoe.lapp //get linking command 1120d35ab615Shenning.noren if(preg_match('/nolink/i',$param)){ 1121dc673a5bSjoe.lapp $linking = 'nolink'; 1122d35ab615Shenning.noren }else if(preg_match('/direct/i',$param)){ 1123dc673a5bSjoe.lapp $linking = 'direct'; 11248acb3108SAndreas Gohr }else if(preg_match('/linkonly/i',$param)){ 11258acb3108SAndreas Gohr $linking = 'linkonly'; 1126dc673a5bSjoe.lapp }else{ 1127dc673a5bSjoe.lapp $linking = 'details'; 1128dc673a5bSjoe.lapp } 1129dc673a5bSjoe.lapp 11304826ab45Sandi //get caching command 11314826ab45Sandi if (preg_match('/(nocache|recache)/i',$param,$cachemode)){ 11324826ab45Sandi $cache = $cachemode[1]; 11330cecf9d5Sandi }else{ 11344826ab45Sandi $cache = 'cache'; 11350cecf9d5Sandi } 11360cecf9d5Sandi 11376efc45a2SDmitry Katsubo // Check whether this is a local or remote image or interwiki 11386efc45a2SDmitry Katsubo if (media_isexternal($src) || link_isinterwiki($src)){ 11394826ab45Sandi $call = 'externalmedia'; 11400cecf9d5Sandi } else { 11414826ab45Sandi $call = 'internalmedia'; 11420cecf9d5Sandi } 11430cecf9d5Sandi 11440cecf9d5Sandi $params = array( 11450cecf9d5Sandi 'type'=>$call, 11464826ab45Sandi 'src'=>$src, 11470cecf9d5Sandi 'title'=>$link[1], 11480cecf9d5Sandi 'align'=>$align, 11494826ab45Sandi 'width'=>$w, 11504826ab45Sandi 'height'=>$h, 11510cecf9d5Sandi 'cache'=>$cache, 1152dc673a5bSjoe.lapp 'linking'=>$linking, 11530cecf9d5Sandi ); 11540cecf9d5Sandi 11550cecf9d5Sandi return $params; 11560cecf9d5Sandi} 11570cecf9d5Sandi 1158