10cecf9d5Sandi<?php 25c2aad12SAndreas Gohr 35c2aad12SAndreas Gohruse dokuwiki\Handler\Block; 45c2aad12SAndreas Gohruse dokuwiki\Handler\CallWriter; 5*8b1b81beSAndreas Gohruse dokuwiki\Handler\CallWriterInterface; 65c2aad12SAndreas Gohruse dokuwiki\Handler\Lists; 75c2aad12SAndreas Gohruse dokuwiki\Handler\Nest; 85c2aad12SAndreas Gohruse dokuwiki\Handler\Preformatted; 95c2aad12SAndreas Gohruse dokuwiki\Handler\Quote; 105c2aad12SAndreas Gohruse dokuwiki\Handler\Table; 115c2aad12SAndreas Gohr 12*8b1b81beSAndreas Gohr/** 13*8b1b81beSAndreas Gohr * Class Doku_Handler 14*8b1b81beSAndreas Gohr */ 150cecf9d5Sandiclass Doku_Handler { 16*8b1b81beSAndreas Gohr /** @var CallWriterInterface */ 17*8b1b81beSAndreas Gohr protected $callWriter = null; 180cecf9d5Sandi 19*8b1b81beSAndreas Gohr /** @var array The current CallWriter will write directly to this list of calls, Parser reads it */ 20*8b1b81beSAndreas Gohr public $calls = array(); 210cecf9d5Sandi 22*8b1b81beSAndreas Gohr /** @var array internal status holders for some modes */ 23*8b1b81beSAndreas Gohr protected $status = array( 2444881bd0Shenning.noren 'section' => false, 25e950d12fSChristopher Smith 'doublequote' => 0, 260cecf9d5Sandi ); 270cecf9d5Sandi 28*8b1b81beSAndreas Gohr /** @var bool should blocks be rewritten? FIXME seems to always be true */ 29*8b1b81beSAndreas Gohr protected $rewriteBlocks = true; 30b7c441b9SHarry Fuecks 31*8b1b81beSAndreas Gohr /** 32*8b1b81beSAndreas Gohr * Doku_Handler constructor. 33*8b1b81beSAndreas Gohr */ 3426e22ab8SChristopher Smith function __construct() { 35*8b1b81beSAndreas Gohr $this->callWriter = new CallWriter($this); 360cecf9d5Sandi } 370cecf9d5Sandi 38276820f7SScrutinizer Auto-Fixer /** 39*8b1b81beSAndreas Gohr * Add a new call by passing it to the current CallWriter 40*8b1b81beSAndreas Gohr * 41*8b1b81beSAndreas Gohr * @param string $handler handler method name (see mode handlers below) 42*8b1b81beSAndreas Gohr * @param mixed $args arguments for this call 43*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 44276820f7SScrutinizer Auto-Fixer */ 45*8b1b81beSAndreas Gohr protected function addCall($handler, $args, $pos) { 460cecf9d5Sandi $call = array($handler,$args, $pos); 47*8b1b81beSAndreas Gohr $this->callWriter->writeCall($call); 480cecf9d5Sandi } 490cecf9d5Sandi 50*8b1b81beSAndreas Gohr /** 51*8b1b81beSAndreas Gohr * Similar to addCall, but adds a plugin call 52*8b1b81beSAndreas Gohr * 53*8b1b81beSAndreas Gohr * @param string $plugin name of the plugin 54*8b1b81beSAndreas Gohr * @param mixed $args arguments for this call 55*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 56*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 57*8b1b81beSAndreas Gohr * @param string $match matched syntax 58*8b1b81beSAndreas Gohr */ 59*8b1b81beSAndreas Gohr protected function addPluginCall($plugin, $args, $state, $pos, $match) { 6082d61635Spierre.spring $call = array('plugin',array($plugin, $args, $state, $match), $pos); 61*8b1b81beSAndreas Gohr $this->callWriter->writeCall($call); 6204ebd214Schris } 6304ebd214Schris 64*8b1b81beSAndreas Gohr /** 65*8b1b81beSAndreas Gohr * Finishes handling 66*8b1b81beSAndreas Gohr * 67*8b1b81beSAndreas Gohr * Called from the parser. Calls finalise() on the call writer, closes open 68*8b1b81beSAndreas Gohr * sections, rewrites blocks and adds document_start and document_end calls. 69*8b1b81beSAndreas Gohr * 70*8b1b81beSAndreas Gohr * @triggers PARSER_HANDLER_DONE 71*8b1b81beSAndreas Gohr */ 72*8b1b81beSAndreas Gohr public function finalize(){ 73*8b1b81beSAndreas Gohr $this->callWriter->finalise(); 74f4f02a0fSchris 75e1c10e4dSchris if ( $this->status['section'] ) { 76e1c10e4dSchris $last_call = end($this->calls); 77e1c10e4dSchris array_push($this->calls,array('section_close',array(), $last_call[2])); 780cecf9d5Sandi } 790cecf9d5Sandi 80b7c441b9SHarry Fuecks if ( $this->rewriteBlocks ) { 815c2aad12SAndreas Gohr $B = new Block(); 820cecf9d5Sandi $this->calls = $B->process($this->calls); 83b7c441b9SHarry Fuecks } 84e0ad864eSchris 8524bb549bSchris trigger_event('PARSER_HANDLER_DONE',$this); 860cecf9d5Sandi 870cecf9d5Sandi array_unshift($this->calls,array('document_start',array(),0)); 880cecf9d5Sandi $last_call = end($this->calls); 890cecf9d5Sandi array_push($this->calls,array('document_end',array(),$last_call[2])); 900cecf9d5Sandi } 910cecf9d5Sandi 929e491c01SAndreas Gohr /** 939e491c01SAndreas Gohr * fetch the current call and advance the pointer to the next one 949e491c01SAndreas Gohr * 95*8b1b81beSAndreas Gohr * @fixme seems to be unused? 969e491c01SAndreas Gohr * @return bool|mixed 979e491c01SAndreas Gohr */ 98*8b1b81beSAndreas Gohr public function fetch() { 999e491c01SAndreas Gohr $call = current($this->calls); 1009e491c01SAndreas Gohr if($call !== false) { 1019e491c01SAndreas Gohr next($this->calls); //advance the pointer 1029e491c01SAndreas Gohr return $call; 1030cecf9d5Sandi } 10444881bd0Shenning.noren return false; 1050cecf9d5Sandi } 106ee20e7d1Sandi 107ee20e7d1Sandi 108ee20e7d1Sandi /** 109e2d88156SLarsDW223 * Internal function for parsing highlight options. 110e2d88156SLarsDW223 * $options is parsed for key value pairs separated by commas. 111e2d88156SLarsDW223 * A value might also be missing in which case the value will simple 112e2d88156SLarsDW223 * be set to true. Commas in strings are ignored, e.g. option="4,56" 113e2d88156SLarsDW223 * will work as expected and will only create one entry. 114e2d88156SLarsDW223 * 11554f741e8SAndreas Gohr * @param string $options space separated list of key-value pairs, 116e2d88156SLarsDW223 * e.g. option1=123, option2="456" 117e2d88156SLarsDW223 * @return array|null Array of key-value pairs $array['key'] = 'value'; 118e2d88156SLarsDW223 * or null if no entries found 119e2d88156SLarsDW223 */ 120e2d88156SLarsDW223 protected function parse_highlight_options ($options) { 121e2d88156SLarsDW223 $result = array(); 12254f741e8SAndreas Gohr preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER); 123e2d88156SLarsDW223 foreach ($matches as $match) { 124e2d88156SLarsDW223 $equal_sign = strpos($match [0], '='); 125e2d88156SLarsDW223 if ($equal_sign === false) { 12654f741e8SAndreas Gohr $key = trim($match[0]); 127e2d88156SLarsDW223 $result [$key] = 1; 128e2d88156SLarsDW223 } else { 129e2d88156SLarsDW223 $key = substr($match[0], 0, $equal_sign); 130e2d88156SLarsDW223 $value = substr($match[0], $equal_sign+1); 131e2d88156SLarsDW223 $value = trim($value, '"'); 132e2d88156SLarsDW223 if (strlen($value) > 0) { 133e2d88156SLarsDW223 $result [$key] = $value; 134e2d88156SLarsDW223 } else { 135e2d88156SLarsDW223 $result [$key] = 1; 136e2d88156SLarsDW223 } 137e2d88156SLarsDW223 } 138e2d88156SLarsDW223 } 139e2d88156SLarsDW223 140e2d88156SLarsDW223 // Check for supported options 141e2d88156SLarsDW223 $result = array_intersect_key( 142e2d88156SLarsDW223 $result, 143e2d88156SLarsDW223 array_flip(array( 144e2d88156SLarsDW223 'enable_line_numbers', 145e2d88156SLarsDW223 'start_line_numbers_at', 146e2d88156SLarsDW223 'highlight_lines_extra', 147e2d88156SLarsDW223 'enable_keyword_links') 148e2d88156SLarsDW223 ) 149e2d88156SLarsDW223 ); 150e2d88156SLarsDW223 151e2d88156SLarsDW223 // Sanitize values 152e2d88156SLarsDW223 if(isset($result['enable_line_numbers'])) { 15354f741e8SAndreas Gohr if($result['enable_line_numbers'] === 'false') { 15454f741e8SAndreas Gohr $result['enable_line_numbers'] = false; 15554f741e8SAndreas Gohr } 156e2d88156SLarsDW223 $result['enable_line_numbers'] = (bool) $result['enable_line_numbers']; 157e2d88156SLarsDW223 } 158e2d88156SLarsDW223 if(isset($result['highlight_lines_extra'])) { 159e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra'])); 160e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']); 161e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']); 162e2d88156SLarsDW223 } 163e2d88156SLarsDW223 if(isset($result['start_line_numbers_at'])) { 164e2d88156SLarsDW223 $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at']; 165e2d88156SLarsDW223 } 166e2d88156SLarsDW223 if(isset($result['enable_keyword_links'])) { 16754f741e8SAndreas Gohr if($result['enable_keyword_links'] === 'false') { 16854f741e8SAndreas Gohr $result['enable_keyword_links'] = false; 16954f741e8SAndreas Gohr } 17054f741e8SAndreas Gohr $result['enable_keyword_links'] = (bool) $result['enable_keyword_links']; 171e2d88156SLarsDW223 } 172e2d88156SLarsDW223 if (count($result) == 0) { 173e2d88156SLarsDW223 return null; 174e2d88156SLarsDW223 } 175e2d88156SLarsDW223 176e2d88156SLarsDW223 return $result; 177e2d88156SLarsDW223 } 178e2d88156SLarsDW223 179*8b1b81beSAndreas Gohr /** 180*8b1b81beSAndreas Gohr * Simplifies handling for the formatting tags which all behave the same 181*8b1b81beSAndreas Gohr * 182*8b1b81beSAndreas Gohr * @param string $match matched syntax 183*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 184*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 185*8b1b81beSAndreas Gohr * @param string $name actual mode name 186*8b1b81beSAndreas Gohr */ 187*8b1b81beSAndreas Gohr protected function nestingTag($match, $state, $pos, $name) { 188*8b1b81beSAndreas Gohr switch ( $state ) { 189*8b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 190*8b1b81beSAndreas Gohr $this->addCall($name.'_open', array(), $pos); 191*8b1b81beSAndreas Gohr break; 192*8b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 193*8b1b81beSAndreas Gohr $this->addCall($name.'_close', array(), $pos); 194*8b1b81beSAndreas Gohr break; 195*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 196*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 197*8b1b81beSAndreas Gohr break; 198*8b1b81beSAndreas Gohr } 199*8b1b81beSAndreas Gohr } 200*8b1b81beSAndreas Gohr 201*8b1b81beSAndreas Gohr 202*8b1b81beSAndreas Gohr /** 203*8b1b81beSAndreas Gohr * The following methods define the handlers for the different Syntax modes 204*8b1b81beSAndreas Gohr * 205*8b1b81beSAndreas Gohr * The handlers are called from dokuwiki\Lexer\Lexer\invokeParser() 206*8b1b81beSAndreas Gohr * 207*8b1b81beSAndreas Gohr * @todo it might make sense to move these into their own class or merge them with the 208*8b1b81beSAndreas Gohr * ParserMode classes some time. 209*8b1b81beSAndreas Gohr */ 210*8b1b81beSAndreas Gohr // region mode handlers 211*8b1b81beSAndreas Gohr 212*8b1b81beSAndreas Gohr /** 213*8b1b81beSAndreas Gohr * Special plugin handler 214*8b1b81beSAndreas Gohr * 215*8b1b81beSAndreas Gohr * This handler is called for all modes starting with 'plugin_'. 216*8b1b81beSAndreas Gohr * An additional parameter with the plugin name is passed. The plugin's handle() 217*8b1b81beSAndreas Gohr * method is called here 218*8b1b81beSAndreas Gohr * 219*8b1b81beSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 220*8b1b81beSAndreas Gohr * 221*8b1b81beSAndreas Gohr * @param string $match matched syntax 222*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 223*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 224*8b1b81beSAndreas Gohr * @param string $pluginname name of the plugin 225*8b1b81beSAndreas Gohr * @return bool mode handled? 226*8b1b81beSAndreas Gohr */ 227*8b1b81beSAndreas Gohr public function plugin($match, $state, $pos, $pluginname){ 228*8b1b81beSAndreas Gohr $data = array($match); 229*8b1b81beSAndreas Gohr /** @var DokuWiki_Syntax_Plugin $plugin */ 230*8b1b81beSAndreas Gohr $plugin = plugin_load('syntax',$pluginname); 231*8b1b81beSAndreas Gohr if($plugin != null){ 232*8b1b81beSAndreas Gohr $data = $plugin->handle($match, $state, $pos, $this); 233*8b1b81beSAndreas Gohr } 234*8b1b81beSAndreas Gohr if ($data !== false) { 235*8b1b81beSAndreas Gohr $this->addPluginCall($pluginname,$data,$state,$pos,$match); 236*8b1b81beSAndreas Gohr } 237*8b1b81beSAndreas Gohr return true; 238*8b1b81beSAndreas Gohr } 239*8b1b81beSAndreas Gohr 240*8b1b81beSAndreas Gohr /** 241*8b1b81beSAndreas Gohr * @param string $match matched syntax 242*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 243*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 244*8b1b81beSAndreas Gohr * @return bool mode handled? 245*8b1b81beSAndreas Gohr */ 246*8b1b81beSAndreas Gohr public function base($match, $state, $pos) { 247*8b1b81beSAndreas Gohr switch ( $state ) { 248*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 249*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 250*8b1b81beSAndreas Gohr return true; 251*8b1b81beSAndreas Gohr break; 252*8b1b81beSAndreas Gohr } 253*8b1b81beSAndreas Gohr return false; 254*8b1b81beSAndreas Gohr } 255*8b1b81beSAndreas Gohr 256*8b1b81beSAndreas Gohr /** 257*8b1b81beSAndreas Gohr * @param string $match matched syntax 258*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 259*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 260*8b1b81beSAndreas Gohr * @return bool mode handled? 261*8b1b81beSAndreas Gohr */ 262*8b1b81beSAndreas Gohr public function header($match, $state, $pos) { 263*8b1b81beSAndreas Gohr // get level and title 264*8b1b81beSAndreas Gohr $title = trim($match); 265*8b1b81beSAndreas Gohr $level = 7 - strspn($title,'='); 266*8b1b81beSAndreas Gohr if($level < 1) $level = 1; 267*8b1b81beSAndreas Gohr $title = trim($title,'='); 268*8b1b81beSAndreas Gohr $title = trim($title); 269*8b1b81beSAndreas Gohr 270*8b1b81beSAndreas Gohr if ($this->status['section']) $this->addCall('section_close', array(), $pos); 271*8b1b81beSAndreas Gohr 272*8b1b81beSAndreas Gohr $this->addCall('header', array($title, $level, $pos), $pos); 273*8b1b81beSAndreas Gohr 274*8b1b81beSAndreas Gohr $this->addCall('section_open', array($level), $pos); 275*8b1b81beSAndreas Gohr $this->status['section'] = true; 276*8b1b81beSAndreas Gohr return true; 277*8b1b81beSAndreas Gohr } 278*8b1b81beSAndreas Gohr 279*8b1b81beSAndreas Gohr /** 280*8b1b81beSAndreas Gohr * @param string $match matched syntax 281*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 282*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 283*8b1b81beSAndreas Gohr * @return bool mode handled? 284*8b1b81beSAndreas Gohr */ 285*8b1b81beSAndreas Gohr public function notoc($match, $state, $pos) { 286*8b1b81beSAndreas Gohr $this->addCall('notoc', array(), $pos); 287*8b1b81beSAndreas Gohr return true; 288*8b1b81beSAndreas Gohr } 289*8b1b81beSAndreas Gohr 290*8b1b81beSAndreas Gohr /** 291*8b1b81beSAndreas Gohr * @param string $match matched syntax 292*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 293*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 294*8b1b81beSAndreas Gohr * @return bool mode handled? 295*8b1b81beSAndreas Gohr */ 296*8b1b81beSAndreas Gohr public function nocache($match, $state, $pos) { 297*8b1b81beSAndreas Gohr $this->addCall('nocache', array(), $pos); 298*8b1b81beSAndreas Gohr return true; 299*8b1b81beSAndreas Gohr } 300*8b1b81beSAndreas Gohr 301*8b1b81beSAndreas Gohr /** 302*8b1b81beSAndreas Gohr * @param string $match matched syntax 303*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 304*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 305*8b1b81beSAndreas Gohr * @return bool mode handled? 306*8b1b81beSAndreas Gohr */ 307*8b1b81beSAndreas Gohr public function linebreak($match, $state, $pos) { 308*8b1b81beSAndreas Gohr $this->addCall('linebreak', array(), $pos); 309*8b1b81beSAndreas Gohr return true; 310*8b1b81beSAndreas Gohr } 311*8b1b81beSAndreas Gohr 312*8b1b81beSAndreas Gohr /** 313*8b1b81beSAndreas Gohr * @param string $match matched syntax 314*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 315*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 316*8b1b81beSAndreas Gohr * @return bool mode handled? 317*8b1b81beSAndreas Gohr */ 318*8b1b81beSAndreas Gohr public function eol($match, $state, $pos) { 319*8b1b81beSAndreas Gohr $this->addCall('eol', array(), $pos); 320*8b1b81beSAndreas Gohr return true; 321*8b1b81beSAndreas Gohr } 322*8b1b81beSAndreas Gohr 323*8b1b81beSAndreas Gohr /** 324*8b1b81beSAndreas Gohr * @param string $match matched syntax 325*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 326*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 327*8b1b81beSAndreas Gohr * @return bool mode handled? 328*8b1b81beSAndreas Gohr */ 329*8b1b81beSAndreas Gohr public function hr($match, $state, $pos) { 330*8b1b81beSAndreas Gohr $this->addCall('hr', array(), $pos); 331*8b1b81beSAndreas Gohr return true; 332*8b1b81beSAndreas Gohr } 333*8b1b81beSAndreas Gohr 334*8b1b81beSAndreas Gohr /** 335*8b1b81beSAndreas Gohr * @param string $match matched syntax 336*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 337*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 338*8b1b81beSAndreas Gohr * @return bool mode handled? 339*8b1b81beSAndreas Gohr */ 340*8b1b81beSAndreas Gohr public function strong($match, $state, $pos) { 341*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'strong'); 342*8b1b81beSAndreas Gohr return true; 343*8b1b81beSAndreas Gohr } 344*8b1b81beSAndreas Gohr 345*8b1b81beSAndreas Gohr /** 346*8b1b81beSAndreas Gohr * @param string $match matched syntax 347*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 348*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 349*8b1b81beSAndreas Gohr * @return bool mode handled? 350*8b1b81beSAndreas Gohr */ 351*8b1b81beSAndreas Gohr public function emphasis($match, $state, $pos) { 352*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'emphasis'); 353*8b1b81beSAndreas Gohr return true; 354*8b1b81beSAndreas Gohr } 355*8b1b81beSAndreas Gohr 356*8b1b81beSAndreas Gohr /** 357*8b1b81beSAndreas Gohr * @param string $match matched syntax 358*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 359*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 360*8b1b81beSAndreas Gohr * @return bool mode handled? 361*8b1b81beSAndreas Gohr */ 362*8b1b81beSAndreas Gohr public function underline($match, $state, $pos) { 363*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'underline'); 364*8b1b81beSAndreas Gohr return true; 365*8b1b81beSAndreas Gohr } 366*8b1b81beSAndreas Gohr 367*8b1b81beSAndreas Gohr /** 368*8b1b81beSAndreas Gohr * @param string $match matched syntax 369*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 370*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 371*8b1b81beSAndreas Gohr * @return bool mode handled? 372*8b1b81beSAndreas Gohr */ 373*8b1b81beSAndreas Gohr public function monospace($match, $state, $pos) { 374*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'monospace'); 375*8b1b81beSAndreas Gohr return true; 376*8b1b81beSAndreas Gohr } 377*8b1b81beSAndreas Gohr 378*8b1b81beSAndreas Gohr /** 379*8b1b81beSAndreas Gohr * @param string $match matched syntax 380*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 381*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 382*8b1b81beSAndreas Gohr * @return bool mode handled? 383*8b1b81beSAndreas Gohr */ 384*8b1b81beSAndreas Gohr public function subscript($match, $state, $pos) { 385*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'subscript'); 386*8b1b81beSAndreas Gohr return true; 387*8b1b81beSAndreas Gohr } 388*8b1b81beSAndreas Gohr 389*8b1b81beSAndreas Gohr /** 390*8b1b81beSAndreas Gohr * @param string $match matched syntax 391*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 392*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 393*8b1b81beSAndreas Gohr * @return bool mode handled? 394*8b1b81beSAndreas Gohr */ 395*8b1b81beSAndreas Gohr public function superscript($match, $state, $pos) { 396*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'superscript'); 397*8b1b81beSAndreas Gohr return true; 398*8b1b81beSAndreas Gohr } 399*8b1b81beSAndreas Gohr 400*8b1b81beSAndreas Gohr /** 401*8b1b81beSAndreas Gohr * @param string $match matched syntax 402*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 403*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 404*8b1b81beSAndreas Gohr * @return bool mode handled? 405*8b1b81beSAndreas Gohr */ 406*8b1b81beSAndreas Gohr public function deleted($match, $state, $pos) { 407*8b1b81beSAndreas Gohr $this->nestingTag($match, $state, $pos, 'deleted'); 408*8b1b81beSAndreas Gohr return true; 409*8b1b81beSAndreas Gohr } 410*8b1b81beSAndreas Gohr 411*8b1b81beSAndreas Gohr /** 412*8b1b81beSAndreas Gohr * @param string $match matched syntax 413*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 414*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 415*8b1b81beSAndreas Gohr * @return bool mode handled? 416*8b1b81beSAndreas Gohr */ 417*8b1b81beSAndreas Gohr public function footnote($match, $state, $pos) { 418*8b1b81beSAndreas Gohr if (!isset($this->_footnote)) $this->_footnote = false; 419*8b1b81beSAndreas Gohr 420*8b1b81beSAndreas Gohr switch ( $state ) { 421*8b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 422*8b1b81beSAndreas Gohr // footnotes can not be nested - however due to limitations in lexer it can't be prevented 423*8b1b81beSAndreas Gohr // we will still enter a new footnote mode, we just do nothing 424*8b1b81beSAndreas Gohr if ($this->_footnote) { 425*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 426*8b1b81beSAndreas Gohr break; 427*8b1b81beSAndreas Gohr } 428*8b1b81beSAndreas Gohr $this->_footnote = true; 429*8b1b81beSAndreas Gohr 430*8b1b81beSAndreas Gohr $this->callWriter = new Nest($this->callWriter, 'footnote_close'); 431*8b1b81beSAndreas Gohr $this->addCall('footnote_open', array(), $pos); 432*8b1b81beSAndreas Gohr break; 433*8b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 434*8b1b81beSAndreas Gohr // check whether we have already exitted the footnote mode, can happen if the modes were nested 435*8b1b81beSAndreas Gohr if (!$this->_footnote) { 436*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 437*8b1b81beSAndreas Gohr break; 438*8b1b81beSAndreas Gohr } 439*8b1b81beSAndreas Gohr 440*8b1b81beSAndreas Gohr $this->_footnote = false; 441*8b1b81beSAndreas Gohr $this->addCall('footnote_close', array(), $pos); 442*8b1b81beSAndreas Gohr 443*8b1b81beSAndreas Gohr /** @var Nest $reWriter */ 444*8b1b81beSAndreas Gohr $reWriter = $this->callWriter; 445*8b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 446*8b1b81beSAndreas Gohr break; 447*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 448*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 449*8b1b81beSAndreas Gohr break; 450*8b1b81beSAndreas Gohr } 451*8b1b81beSAndreas Gohr return true; 452*8b1b81beSAndreas Gohr } 453*8b1b81beSAndreas Gohr 454*8b1b81beSAndreas Gohr /** 455*8b1b81beSAndreas Gohr * @param string $match matched syntax 456*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 457*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 458*8b1b81beSAndreas Gohr * @return bool mode handled? 459*8b1b81beSAndreas Gohr */ 460*8b1b81beSAndreas Gohr public function listblock($match, $state, $pos) { 461*8b1b81beSAndreas Gohr switch ( $state ) { 462*8b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 463*8b1b81beSAndreas Gohr $this->callWriter = new Lists($this->callWriter); 464*8b1b81beSAndreas Gohr $this->addCall('list_open', array($match), $pos); 465*8b1b81beSAndreas Gohr break; 466*8b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 467*8b1b81beSAndreas Gohr $this->addCall('list_close', array(), $pos); 468*8b1b81beSAndreas Gohr /** @var Lists $reWriter */ 469*8b1b81beSAndreas Gohr $reWriter = $this->callWriter; 470*8b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 471*8b1b81beSAndreas Gohr break; 472*8b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 473*8b1b81beSAndreas Gohr $this->addCall('list_item', array($match), $pos); 474*8b1b81beSAndreas Gohr break; 475*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 476*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 477*8b1b81beSAndreas Gohr break; 478*8b1b81beSAndreas Gohr } 479*8b1b81beSAndreas Gohr return true; 480*8b1b81beSAndreas Gohr } 481*8b1b81beSAndreas Gohr 482*8b1b81beSAndreas Gohr /** 483*8b1b81beSAndreas Gohr * @param string $match matched syntax 484*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 485*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 486*8b1b81beSAndreas Gohr * @return bool mode handled? 487*8b1b81beSAndreas Gohr */ 488*8b1b81beSAndreas Gohr public function unformatted($match, $state, $pos) { 489*8b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 490*8b1b81beSAndreas Gohr $this->addCall('unformatted', array($match), $pos); 491*8b1b81beSAndreas Gohr } 492*8b1b81beSAndreas Gohr return true; 493*8b1b81beSAndreas Gohr } 494*8b1b81beSAndreas Gohr 495*8b1b81beSAndreas Gohr /** 496*8b1b81beSAndreas Gohr * @param string $match matched syntax 497*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 498*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 499*8b1b81beSAndreas Gohr * @return bool mode handled? 500*8b1b81beSAndreas Gohr */ 501*8b1b81beSAndreas Gohr public function php($match, $state, $pos) { 502*8b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 503*8b1b81beSAndreas Gohr $this->addCall('php', array($match), $pos); 504*8b1b81beSAndreas Gohr } 505*8b1b81beSAndreas Gohr return true; 506*8b1b81beSAndreas Gohr } 507*8b1b81beSAndreas Gohr 508*8b1b81beSAndreas Gohr /** 509*8b1b81beSAndreas Gohr * @param string $match matched syntax 510*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 511*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 512*8b1b81beSAndreas Gohr * @return bool mode handled? 513*8b1b81beSAndreas Gohr */ 514*8b1b81beSAndreas Gohr public function phpblock($match, $state, $pos) { 515*8b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 516*8b1b81beSAndreas Gohr $this->addCall('phpblock', array($match), $pos); 517*8b1b81beSAndreas Gohr } 518*8b1b81beSAndreas Gohr return true; 519*8b1b81beSAndreas Gohr } 520*8b1b81beSAndreas Gohr 521*8b1b81beSAndreas Gohr /** 522*8b1b81beSAndreas Gohr * @param string $match matched syntax 523*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 524*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 525*8b1b81beSAndreas Gohr * @return bool mode handled? 526*8b1b81beSAndreas Gohr */ 527*8b1b81beSAndreas Gohr public function html($match, $state, $pos) { 528*8b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 529*8b1b81beSAndreas Gohr $this->addCall('html', array($match), $pos); 530*8b1b81beSAndreas Gohr } 531*8b1b81beSAndreas Gohr return true; 532*8b1b81beSAndreas Gohr } 533*8b1b81beSAndreas Gohr 534*8b1b81beSAndreas Gohr /** 535*8b1b81beSAndreas Gohr * @param string $match matched syntax 536*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 537*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 538*8b1b81beSAndreas Gohr * @return bool mode handled? 539*8b1b81beSAndreas Gohr */ 540*8b1b81beSAndreas Gohr public function htmlblock($match, $state, $pos) { 541*8b1b81beSAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 542*8b1b81beSAndreas Gohr $this->addCall('htmlblock', array($match), $pos); 543*8b1b81beSAndreas Gohr } 544*8b1b81beSAndreas Gohr return true; 545*8b1b81beSAndreas Gohr } 546*8b1b81beSAndreas Gohr 547*8b1b81beSAndreas Gohr /** 548*8b1b81beSAndreas Gohr * @param string $match matched syntax 549*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 550*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 551*8b1b81beSAndreas Gohr * @return bool mode handled? 552*8b1b81beSAndreas Gohr */ 553*8b1b81beSAndreas Gohr public function preformatted($match, $state, $pos) { 554*8b1b81beSAndreas Gohr switch ( $state ) { 555*8b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 556*8b1b81beSAndreas Gohr $this->callWriter = new Preformatted($this->callWriter); 557*8b1b81beSAndreas Gohr $this->addCall('preformatted_start', array(), $pos); 558*8b1b81beSAndreas Gohr break; 559*8b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 560*8b1b81beSAndreas Gohr $this->addCall('preformatted_end', array(), $pos); 561*8b1b81beSAndreas Gohr /** @var Preformatted $reWriter */ 562*8b1b81beSAndreas Gohr $reWriter = $this->callWriter; 563*8b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 564*8b1b81beSAndreas Gohr break; 565*8b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 566*8b1b81beSAndreas Gohr $this->addCall('preformatted_newline', array(), $pos); 567*8b1b81beSAndreas Gohr break; 568*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 569*8b1b81beSAndreas Gohr $this->addCall('preformatted_content', array($match), $pos); 570*8b1b81beSAndreas Gohr break; 571*8b1b81beSAndreas Gohr } 572*8b1b81beSAndreas Gohr 573*8b1b81beSAndreas Gohr return true; 574*8b1b81beSAndreas Gohr } 575*8b1b81beSAndreas Gohr 576*8b1b81beSAndreas Gohr /** 577*8b1b81beSAndreas Gohr * @param string $match matched syntax 578*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 579*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 580*8b1b81beSAndreas Gohr * @return bool mode handled? 581*8b1b81beSAndreas Gohr */ 582*8b1b81beSAndreas Gohr public function quote($match, $state, $pos) { 583*8b1b81beSAndreas Gohr 584*8b1b81beSAndreas Gohr switch ( $state ) { 585*8b1b81beSAndreas Gohr 586*8b1b81beSAndreas Gohr case DOKU_LEXER_ENTER: 587*8b1b81beSAndreas Gohr $this->callWriter = new Quote($this->callWriter); 588*8b1b81beSAndreas Gohr $this->addCall('quote_start', array($match), $pos); 589*8b1b81beSAndreas Gohr break; 590*8b1b81beSAndreas Gohr 591*8b1b81beSAndreas Gohr case DOKU_LEXER_EXIT: 592*8b1b81beSAndreas Gohr $this->addCall('quote_end', array(), $pos); 593*8b1b81beSAndreas Gohr /** @var Lists $reWriter */ 594*8b1b81beSAndreas Gohr $reWriter = $this->callWriter; 595*8b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 596*8b1b81beSAndreas Gohr break; 597*8b1b81beSAndreas Gohr 598*8b1b81beSAndreas Gohr case DOKU_LEXER_MATCHED: 599*8b1b81beSAndreas Gohr $this->addCall('quote_newline', array($match), $pos); 600*8b1b81beSAndreas Gohr break; 601*8b1b81beSAndreas Gohr 602*8b1b81beSAndreas Gohr case DOKU_LEXER_UNMATCHED: 603*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 604*8b1b81beSAndreas Gohr break; 605*8b1b81beSAndreas Gohr 606*8b1b81beSAndreas Gohr } 607*8b1b81beSAndreas Gohr 608*8b1b81beSAndreas Gohr return true; 609*8b1b81beSAndreas Gohr } 610*8b1b81beSAndreas Gohr 611*8b1b81beSAndreas Gohr /** 612*8b1b81beSAndreas Gohr * @param string $match matched syntax 613*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 614*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 615*8b1b81beSAndreas Gohr * @return bool mode handled? 616*8b1b81beSAndreas Gohr */ 617*8b1b81beSAndreas Gohr public function file($match, $state, $pos) { 6183d491f75SAndreas Gohr return $this->code($match, $state, $pos, 'file'); 6193d491f75SAndreas Gohr } 6203d491f75SAndreas Gohr 621*8b1b81beSAndreas Gohr /** 622*8b1b81beSAndreas Gohr * @param string $match matched syntax 623*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 624*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 625*8b1b81beSAndreas Gohr * @param string $type either 'code' or 'file' 626*8b1b81beSAndreas Gohr * @return bool mode handled? 627*8b1b81beSAndreas Gohr */ 628*8b1b81beSAndreas Gohr public function code($match, $state, $pos, $type='code') { 6293d491f75SAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 6304b7f9e70STom N Harris $matches = explode('>',$match,2); 631e2d88156SLarsDW223 // Cut out variable options enclosed in [] 632e2d88156SLarsDW223 preg_match('/\[.*\]/', $matches[0], $options); 633e2d88156SLarsDW223 if (!empty($options[0])) { 634e2d88156SLarsDW223 $matches[0] = str_replace($options[0], '', $matches[0]); 635e2d88156SLarsDW223 } 6360139312bSAdrian Lang $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY); 6370139312bSAdrian Lang while(count($param) < 2) array_push($param, null); 6380139312bSAdrian Lang // We shortcut html here. 6390139312bSAdrian Lang if ($param[0] == 'html') $param[0] = 'html4strict'; 6400139312bSAdrian Lang if ($param[0] == '-') $param[0] = null; 6410139312bSAdrian Lang array_unshift($param, $matches[1]); 642e2d88156SLarsDW223 if (!empty($options[0])) { 643e2d88156SLarsDW223 $param [] = $this->parse_highlight_options ($options[0]); 644e2d88156SLarsDW223 } 645*8b1b81beSAndreas Gohr $this->addCall($type, $param, $pos); 6460cecf9d5Sandi } 64744881bd0Shenning.noren return true; 6480cecf9d5Sandi } 6490cecf9d5Sandi 650*8b1b81beSAndreas Gohr /** 651*8b1b81beSAndreas Gohr * @param string $match matched syntax 652*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 653*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 654*8b1b81beSAndreas Gohr * @return bool mode handled? 655*8b1b81beSAndreas Gohr */ 656*8b1b81beSAndreas Gohr public function acronym($match, $state, $pos) { 657*8b1b81beSAndreas Gohr $this->addCall('acronym', array($match), $pos); 65844881bd0Shenning.noren return true; 6590cecf9d5Sandi } 6600cecf9d5Sandi 661*8b1b81beSAndreas Gohr /** 662*8b1b81beSAndreas Gohr * @param string $match matched syntax 663*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 664*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 665*8b1b81beSAndreas Gohr * @return bool mode handled? 666*8b1b81beSAndreas Gohr */ 667*8b1b81beSAndreas Gohr public function smiley($match, $state, $pos) { 668*8b1b81beSAndreas Gohr $this->addCall('smiley', array($match), $pos); 66944881bd0Shenning.noren return true; 6700cecf9d5Sandi } 6710cecf9d5Sandi 672*8b1b81beSAndreas Gohr /** 673*8b1b81beSAndreas Gohr * @param string $match matched syntax 674*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 675*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 676*8b1b81beSAndreas Gohr * @return bool mode handled? 677*8b1b81beSAndreas Gohr */ 678*8b1b81beSAndreas Gohr public function wordblock($match, $state, $pos) { 679*8b1b81beSAndreas Gohr $this->addCall('wordblock', array($match), $pos); 68044881bd0Shenning.noren return true; 6810cecf9d5Sandi } 6820cecf9d5Sandi 683*8b1b81beSAndreas Gohr /** 684*8b1b81beSAndreas Gohr * @param string $match matched syntax 685*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 686*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 687*8b1b81beSAndreas Gohr * @return bool mode handled? 688*8b1b81beSAndreas Gohr */ 689*8b1b81beSAndreas Gohr public function entity($match, $state, $pos) { 690*8b1b81beSAndreas Gohr $this->addCall('entity', array($match), $pos); 69144881bd0Shenning.noren return true; 6920cecf9d5Sandi } 6930cecf9d5Sandi 694*8b1b81beSAndreas Gohr /** 695*8b1b81beSAndreas Gohr * @param string $match matched syntax 696*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 697*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 698*8b1b81beSAndreas Gohr * @return bool mode handled? 699*8b1b81beSAndreas Gohr */ 700*8b1b81beSAndreas Gohr public function multiplyentity($match, $state, $pos) { 7010cecf9d5Sandi preg_match_all('/\d+/',$match,$matches); 702*8b1b81beSAndreas Gohr $this->addCall('multiplyentity', array($matches[0][0], $matches[0][1]), $pos); 70344881bd0Shenning.noren return true; 7040cecf9d5Sandi } 7050cecf9d5Sandi 706*8b1b81beSAndreas Gohr /** 707*8b1b81beSAndreas Gohr * @param string $match matched syntax 708*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 709*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 710*8b1b81beSAndreas Gohr * @return bool mode handled? 711*8b1b81beSAndreas Gohr */ 712*8b1b81beSAndreas Gohr public function singlequoteopening($match, $state, $pos) { 713*8b1b81beSAndreas Gohr $this->addCall('singlequoteopening', array(), $pos); 71444881bd0Shenning.noren return true; 7150cecf9d5Sandi } 7160cecf9d5Sandi 717*8b1b81beSAndreas Gohr /** 718*8b1b81beSAndreas Gohr * @param string $match matched syntax 719*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 720*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 721*8b1b81beSAndreas Gohr * @return bool mode handled? 722*8b1b81beSAndreas Gohr */ 723*8b1b81beSAndreas Gohr public function singlequoteclosing($match, $state, $pos) { 724*8b1b81beSAndreas Gohr $this->addCall('singlequoteclosing', array(), $pos); 72544881bd0Shenning.noren return true; 7260cecf9d5Sandi } 7270cecf9d5Sandi 728*8b1b81beSAndreas Gohr /** 729*8b1b81beSAndreas Gohr * @param string $match matched syntax 730*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 731*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 732*8b1b81beSAndreas Gohr * @return bool mode handled? 733*8b1b81beSAndreas Gohr */ 734*8b1b81beSAndreas Gohr public function apostrophe($match, $state, $pos) { 735*8b1b81beSAndreas Gohr $this->addCall('apostrophe', array(), $pos); 73657d757d1SAndreas Gohr return true; 73757d757d1SAndreas Gohr } 73857d757d1SAndreas Gohr 739*8b1b81beSAndreas Gohr /** 740*8b1b81beSAndreas Gohr * @param string $match matched syntax 741*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 742*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 743*8b1b81beSAndreas Gohr * @return bool mode handled? 744*8b1b81beSAndreas Gohr */ 745*8b1b81beSAndreas Gohr public function doublequoteopening($match, $state, $pos) { 746*8b1b81beSAndreas Gohr $this->addCall('doublequoteopening', array(), $pos); 747e950d12fSChristopher Smith $this->status['doublequote']++; 74844881bd0Shenning.noren return true; 7490cecf9d5Sandi } 7500cecf9d5Sandi 751*8b1b81beSAndreas Gohr /** 752*8b1b81beSAndreas Gohr * @param string $match matched syntax 753*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 754*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 755*8b1b81beSAndreas Gohr * @return bool mode handled? 756*8b1b81beSAndreas Gohr */ 757*8b1b81beSAndreas Gohr public function doublequoteclosing($match, $state, $pos) { 758e950d12fSChristopher Smith if ($this->status['doublequote'] <= 0) { 759e950d12fSChristopher Smith $this->doublequoteopening($match, $state, $pos); 760e950d12fSChristopher Smith } else { 761*8b1b81beSAndreas Gohr $this->addCall('doublequoteclosing', array(), $pos); 762e950d12fSChristopher Smith $this->status['doublequote'] = max(0, --$this->status['doublequote']); 763e950d12fSChristopher Smith } 76444881bd0Shenning.noren return true; 7650cecf9d5Sandi } 7660cecf9d5Sandi 767*8b1b81beSAndreas Gohr /** 768*8b1b81beSAndreas Gohr * @param string $match matched syntax 769*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 770*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 771*8b1b81beSAndreas Gohr * @return bool mode handled? 772*8b1b81beSAndreas Gohr */ 773*8b1b81beSAndreas Gohr public function camelcaselink($match, $state, $pos) { 774*8b1b81beSAndreas Gohr $this->addCall('camelcaselink', array($match), $pos); 77544881bd0Shenning.noren return true; 7760cecf9d5Sandi } 7770cecf9d5Sandi 778*8b1b81beSAndreas Gohr /** 779*8b1b81beSAndreas Gohr * @param string $match matched syntax 780*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 781*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 782*8b1b81beSAndreas Gohr * @return bool mode handled? 7830cecf9d5Sandi */ 784*8b1b81beSAndreas Gohr public function internallink($match, $state, $pos) { 7850cecf9d5Sandi // Strip the opening and closing markup 7860cecf9d5Sandi $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); 7870cecf9d5Sandi 7880cecf9d5Sandi // Split title from URL 7894b7f9e70STom N Harris $link = explode('|',$link,2); 7900cecf9d5Sandi if ( !isset($link[1]) ) { 7910ea51e63SMatt Perry $link[1] = null; 7920cecf9d5Sandi } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) { 7935578eb8fSandi // If the title is an image, convert it to an array containing the image details 794b625487dSandi $link[1] = Doku_Handler_Parse_Media($link[1]); 7950cecf9d5Sandi } 7960b7c14c2Sandi $link[0] = trim($link[0]); 7970cecf9d5Sandi 7980e1c636eSandi //decide which kind of link it is 7990e1c636eSandi 8006efc45a2SDmitry Katsubo if ( link_isinterwiki($link[0]) ) { 8010e1c636eSandi // Interwiki 8024b7f9e70STom N Harris $interwiki = explode('>',$link[0],2); 803*8b1b81beSAndreas Gohr $this->addCall( 8040cecf9d5Sandi 'interwikilink', 8050cecf9d5Sandi array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), 8060cecf9d5Sandi $pos 8070cecf9d5Sandi ); 80815f1b77cSAndreas Gohr }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { 8090e1c636eSandi // Windows Share 810*8b1b81beSAndreas Gohr $this->addCall( 8110cecf9d5Sandi 'windowssharelink', 8120cecf9d5Sandi array($link[0],$link[1]), 8130cecf9d5Sandi $pos 8140cecf9d5Sandi ); 8154468cb4cSAndreas Gohr }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) { 8160e1c636eSandi // external link (accepts all protocols) 817*8b1b81beSAndreas Gohr $this->addCall( 8180cecf9d5Sandi 'externallink', 8190cecf9d5Sandi array($link[0],$link[1]), 8200cecf9d5Sandi $pos 8210cecf9d5Sandi ); 8220a1d30bfSchris }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) { 8230a1d30bfSchris // E-Mail (pattern above is defined in inc/mail.php) 824*8b1b81beSAndreas Gohr $this->addCall( 825a6755281Sandi 'emaillink', 826a6755281Sandi array($link[0],$link[1]), 827a6755281Sandi $pos 828a6755281Sandi ); 8290b7c14c2Sandi }elseif ( preg_match('!^#.+!',$link[0]) ){ 8300b7c14c2Sandi // local link 831*8b1b81beSAndreas Gohr $this->addCall( 8320b7c14c2Sandi 'locallink', 8330b7c14c2Sandi array(substr($link[0],1),$link[1]), 8340b7c14c2Sandi $pos 8350b7c14c2Sandi ); 8360e1c636eSandi }else{ 8370e1c636eSandi // internal link 838*8b1b81beSAndreas Gohr $this->addCall( 8390e1c636eSandi 'internallink', 8400e1c636eSandi array($link[0],$link[1]), 8410e1c636eSandi $pos 8420e1c636eSandi ); 8430cecf9d5Sandi } 8440e1c636eSandi 84544881bd0Shenning.noren return true; 8460cecf9d5Sandi } 8470cecf9d5Sandi 848*8b1b81beSAndreas Gohr /** 849*8b1b81beSAndreas Gohr * @param string $match matched syntax 850*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 851*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 852*8b1b81beSAndreas Gohr * @return bool mode handled? 853*8b1b81beSAndreas Gohr */ 854*8b1b81beSAndreas Gohr public function filelink($match, $state, $pos) { 855*8b1b81beSAndreas Gohr $this->addCall('filelink', array($match, null), $pos); 85644881bd0Shenning.noren return true; 8570cecf9d5Sandi } 8580cecf9d5Sandi 859*8b1b81beSAndreas Gohr /** 860*8b1b81beSAndreas Gohr * @param string $match matched syntax 861*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 862*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 863*8b1b81beSAndreas Gohr * @return bool mode handled? 864*8b1b81beSAndreas Gohr */ 865*8b1b81beSAndreas Gohr public function windowssharelink($match, $state, $pos) { 866*8b1b81beSAndreas Gohr $this->addCall('windowssharelink', array($match, null), $pos); 86744881bd0Shenning.noren return true; 8680cecf9d5Sandi } 8690cecf9d5Sandi 870*8b1b81beSAndreas Gohr /** 871*8b1b81beSAndreas Gohr * @param string $match matched syntax 872*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 873*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 874*8b1b81beSAndreas Gohr * @return bool mode handled? 875*8b1b81beSAndreas Gohr */ 876*8b1b81beSAndreas Gohr public function media($match, $state, $pos) { 8770cecf9d5Sandi $p = Doku_Handler_Parse_Media($match); 8780cecf9d5Sandi 879*8b1b81beSAndreas Gohr $this->addCall( 8800cecf9d5Sandi $p['type'], 881dc673a5bSjoe.lapp array($p['src'], $p['title'], $p['align'], $p['width'], 882dc673a5bSjoe.lapp $p['height'], $p['cache'], $p['linking']), 8830cecf9d5Sandi $pos 8840cecf9d5Sandi ); 88544881bd0Shenning.noren return true; 8860cecf9d5Sandi } 8870cecf9d5Sandi 888*8b1b81beSAndreas Gohr /** 889*8b1b81beSAndreas Gohr * @param string $match matched syntax 890*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 891*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 892*8b1b81beSAndreas Gohr * @return bool mode handled? 893*8b1b81beSAndreas Gohr */ 894*8b1b81beSAndreas Gohr public function rss($match, $state, $pos) { 895b625487dSandi $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); 8963db95becSAndreas Gohr 8973db95becSAndreas Gohr // get params 8983db95becSAndreas Gohr list($link,$params) = explode(' ',$link,2); 8993db95becSAndreas Gohr 9003db95becSAndreas Gohr $p = array(); 9013db95becSAndreas Gohr if(preg_match('/\b(\d+)\b/',$params,$match)){ 9023db95becSAndreas Gohr $p['max'] = $match[1]; 9033db95becSAndreas Gohr }else{ 9043db95becSAndreas Gohr $p['max'] = 8; 9053db95becSAndreas Gohr } 9063db95becSAndreas Gohr $p['reverse'] = (preg_match('/rev/',$params)); 9073db95becSAndreas Gohr $p['author'] = (preg_match('/\b(by|author)/',$params)); 9083db95becSAndreas Gohr $p['date'] = (preg_match('/\b(date)/',$params)); 9093db95becSAndreas Gohr $p['details'] = (preg_match('/\b(desc|detail)/',$params)); 91038c6f603SRobin H. Johnson $p['nosort'] = (preg_match('/\b(nosort)\b/',$params)); 9113db95becSAndreas Gohr 9120a69dff7Schris if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) { 9130a69dff7Schris $period = array('d' => 86400, 'h' => 3600, 'm' => 60); 9140a69dff7Schris $p['refresh'] = max(600,$match[1]*$period[$match[2]]); // n * period in seconds, minimum 10 minutes 9150a69dff7Schris } else { 9160a69dff7Schris $p['refresh'] = 14400; // default to 4 hours 9170a69dff7Schris } 9180a69dff7Schris 919*8b1b81beSAndreas Gohr $this->addCall('rss', array($link, $p), $pos); 92044881bd0Shenning.noren return true; 921b625487dSandi } 922b625487dSandi 923*8b1b81beSAndreas Gohr /** 924*8b1b81beSAndreas Gohr * @param string $match matched syntax 925*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 926*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 927*8b1b81beSAndreas Gohr * @return bool mode handled? 928*8b1b81beSAndreas Gohr */ 929*8b1b81beSAndreas Gohr public function externallink($match, $state, $pos) { 930da9f31c5SAndreas Gohr $url = $match; 931da9f31c5SAndreas Gohr $title = null; 9320cecf9d5Sandi 933da9f31c5SAndreas Gohr // add protocol on simple short URLs 934da9f31c5SAndreas Gohr if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){ 935da9f31c5SAndreas Gohr $title = $url; 936da9f31c5SAndreas Gohr $url = 'ftp://'.$url; 937da9f31c5SAndreas Gohr } 938da9f31c5SAndreas Gohr if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){ 939da9f31c5SAndreas Gohr $title = $url; 940da9f31c5SAndreas Gohr $url = 'http://'.$url; 941da9f31c5SAndreas Gohr } 942da9f31c5SAndreas Gohr 943*8b1b81beSAndreas Gohr $this->addCall('externallink', array($url, $title), $pos); 94444881bd0Shenning.noren return true; 9450cecf9d5Sandi } 9460cecf9d5Sandi 947*8b1b81beSAndreas Gohr /** 948*8b1b81beSAndreas Gohr * @param string $match matched syntax 949*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 950*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 951*8b1b81beSAndreas Gohr * @return bool mode handled? 952*8b1b81beSAndreas Gohr */ 953*8b1b81beSAndreas Gohr public function emaillink($match, $state, $pos) { 9540cecf9d5Sandi $email = preg_replace(array('/^</','/>$/'),'',$match); 955*8b1b81beSAndreas Gohr $this->addCall('emaillink', array($email, null), $pos); 95644881bd0Shenning.noren return true; 9570cecf9d5Sandi } 9580cecf9d5Sandi 959*8b1b81beSAndreas Gohr /** 960*8b1b81beSAndreas Gohr * @param string $match matched syntax 961*8b1b81beSAndreas Gohr * @param int $state a LEXER_STATE_* constant 962*8b1b81beSAndreas Gohr * @param int $pos byte position in the original source file 963*8b1b81beSAndreas Gohr * @return bool mode handled? 964*8b1b81beSAndreas Gohr */ 965*8b1b81beSAndreas Gohr public function table($match, $state, $pos) { 9660cecf9d5Sandi switch ( $state ) { 9670cecf9d5Sandi 9680cecf9d5Sandi case DOKU_LEXER_ENTER: 9690cecf9d5Sandi 970*8b1b81beSAndreas Gohr $this->callWriter = new Table($this->callWriter); 9710cecf9d5Sandi 972*8b1b81beSAndreas Gohr $this->addCall('table_start', array($pos + 1), $pos); 9730cecf9d5Sandi if ( trim($match) == '^' ) { 974*8b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 9750cecf9d5Sandi } else { 976*8b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 9770cecf9d5Sandi } 9780cecf9d5Sandi break; 9790cecf9d5Sandi 9800cecf9d5Sandi case DOKU_LEXER_EXIT: 981*8b1b81beSAndreas Gohr $this->addCall('table_end', array($pos), $pos); 9825c2aad12SAndreas Gohr /** @var Table $reWriter */ 983*8b1b81beSAndreas Gohr $reWriter = $this->callWriter; 984*8b1b81beSAndreas Gohr $this->callWriter = $reWriter->process(); 9850cecf9d5Sandi break; 9860cecf9d5Sandi 9870cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 9880cecf9d5Sandi if ( trim($match) != '' ) { 989*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 9900cecf9d5Sandi } 9910cecf9d5Sandi break; 9920cecf9d5Sandi 9930cecf9d5Sandi case DOKU_LEXER_MATCHED: 9949ab75d9eSAndreas Gohr if ( $match == ' ' ){ 995*8b1b81beSAndreas Gohr $this->addCall('cdata', array($match), $pos); 99625b97867Shakan.sandell } else if ( preg_match('/:::/',$match) ) { 997*8b1b81beSAndreas Gohr $this->addCall('rowspan', array($match), $pos); 998e205b721SAndreas Gohr } else if ( preg_match('/\t+/',$match) ) { 999*8b1b81beSAndreas Gohr $this->addCall('table_align', array($match), $pos); 1000e205b721SAndreas Gohr } else if ( preg_match('/ {2,}/',$match) ) { 1001*8b1b81beSAndreas Gohr $this->addCall('table_align', array($match), $pos); 10020cecf9d5Sandi } else if ( $match == "\n|" ) { 1003*8b1b81beSAndreas Gohr $this->addCall('table_row', array(), $pos); 1004*8b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 10050cecf9d5Sandi } else if ( $match == "\n^" ) { 1006*8b1b81beSAndreas Gohr $this->addCall('table_row', array(), $pos); 1007*8b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 10080cecf9d5Sandi } else if ( $match == '|' ) { 1009*8b1b81beSAndreas Gohr $this->addCall('tablecell', array(), $pos); 10100cecf9d5Sandi } else if ( $match == '^' ) { 1011*8b1b81beSAndreas Gohr $this->addCall('tableheader', array(), $pos); 10120cecf9d5Sandi } 10130cecf9d5Sandi break; 10140cecf9d5Sandi } 101544881bd0Shenning.noren return true; 10160cecf9d5Sandi } 1017*8b1b81beSAndreas Gohr 1018*8b1b81beSAndreas Gohr // endregion modes 10190cecf9d5Sandi} 10200cecf9d5Sandi 10210cecf9d5Sandi//------------------------------------------------------------------------ 10220cecf9d5Sandifunction Doku_Handler_Parse_Media($match) { 10230cecf9d5Sandi 10240cecf9d5Sandi // Strip the opening and closing markup 10250cecf9d5Sandi $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); 10260cecf9d5Sandi 10270cecf9d5Sandi // Split title from URL 10284b7f9e70STom N Harris $link = explode('|',$link,2); 10290cecf9d5Sandi 10300cecf9d5Sandi // Check alignment 10310cecf9d5Sandi $ralign = (bool)preg_match('/^ /',$link[0]); 10320cecf9d5Sandi $lalign = (bool)preg_match('/ $/',$link[0]); 10330cecf9d5Sandi 10340cecf9d5Sandi // Logic = what's that ;)... 10350cecf9d5Sandi if ( $lalign & $ralign ) { 10360cecf9d5Sandi $align = 'center'; 10370cecf9d5Sandi } else if ( $ralign ) { 10380cecf9d5Sandi $align = 'right'; 10390cecf9d5Sandi } else if ( $lalign ) { 10400cecf9d5Sandi $align = 'left'; 10410cecf9d5Sandi } else { 10420ea51e63SMatt Perry $align = null; 10430cecf9d5Sandi } 10440cecf9d5Sandi 10450cecf9d5Sandi // The title... 10460cecf9d5Sandi if ( !isset($link[1]) ) { 10470ea51e63SMatt Perry $link[1] = null; 10480cecf9d5Sandi } 10490cecf9d5Sandi 10504826ab45Sandi //remove aligning spaces 10514826ab45Sandi $link[0] = trim($link[0]); 10520cecf9d5Sandi 10534826ab45Sandi //split into src and parameters (using the very last questionmark) 10544826ab45Sandi $pos = strrpos($link[0], '?'); 10554826ab45Sandi if($pos !== false){ 10564826ab45Sandi $src = substr($link[0],0,$pos); 10574826ab45Sandi $param = substr($link[0],$pos+1); 10580cecf9d5Sandi }else{ 10594826ab45Sandi $src = $link[0]; 10604826ab45Sandi $param = ''; 10610cecf9d5Sandi } 10620cecf9d5Sandi 10634826ab45Sandi //parse width and height 10644826ab45Sandi if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){ 1065443e135dSChristopher Smith !empty($size[1]) ? $w = $size[1] : $w = null; 1066443e135dSChristopher Smith !empty($size[3]) ? $h = $size[3] : $h = null; 1067fc1c55b1Shfuecks } else { 10680ea51e63SMatt Perry $w = null; 10690ea51e63SMatt Perry $h = null; 10700cecf9d5Sandi } 10710cecf9d5Sandi 1072dc673a5bSjoe.lapp //get linking command 1073d35ab615Shenning.noren if(preg_match('/nolink/i',$param)){ 1074dc673a5bSjoe.lapp $linking = 'nolink'; 1075d35ab615Shenning.noren }else if(preg_match('/direct/i',$param)){ 1076dc673a5bSjoe.lapp $linking = 'direct'; 10778acb3108SAndreas Gohr }else if(preg_match('/linkonly/i',$param)){ 10788acb3108SAndreas Gohr $linking = 'linkonly'; 1079dc673a5bSjoe.lapp }else{ 1080dc673a5bSjoe.lapp $linking = 'details'; 1081dc673a5bSjoe.lapp } 1082dc673a5bSjoe.lapp 10834826ab45Sandi //get caching command 10844826ab45Sandi if (preg_match('/(nocache|recache)/i',$param,$cachemode)){ 10854826ab45Sandi $cache = $cachemode[1]; 10860cecf9d5Sandi }else{ 10874826ab45Sandi $cache = 'cache'; 10880cecf9d5Sandi } 10890cecf9d5Sandi 10906efc45a2SDmitry Katsubo // Check whether this is a local or remote image or interwiki 10916efc45a2SDmitry Katsubo if (media_isexternal($src) || link_isinterwiki($src)){ 10924826ab45Sandi $call = 'externalmedia'; 10930cecf9d5Sandi } else { 10944826ab45Sandi $call = 'internalmedia'; 10950cecf9d5Sandi } 10960cecf9d5Sandi 10970cecf9d5Sandi $params = array( 10980cecf9d5Sandi 'type'=>$call, 10994826ab45Sandi 'src'=>$src, 11000cecf9d5Sandi 'title'=>$link[1], 11010cecf9d5Sandi 'align'=>$align, 11024826ab45Sandi 'width'=>$w, 11034826ab45Sandi 'height'=>$h, 11040cecf9d5Sandi 'cache'=>$cache, 1105dc673a5bSjoe.lapp 'linking'=>$linking, 11060cecf9d5Sandi ); 11070cecf9d5Sandi 11080cecf9d5Sandi return $params; 11090cecf9d5Sandi} 11100cecf9d5Sandi 1111