10cecf9d5Sandi<?php 2*5c2aad12SAndreas Gohr 3*5c2aad12SAndreas Gohruse dokuwiki\Handler\Block; 4*5c2aad12SAndreas Gohruse dokuwiki\Handler\CallWriter; 5*5c2aad12SAndreas Gohruse dokuwiki\Handler\Lists; 6*5c2aad12SAndreas Gohruse dokuwiki\Handler\Nest; 7*5c2aad12SAndreas Gohruse dokuwiki\Handler\Preformatted; 8*5c2aad12SAndreas Gohruse dokuwiki\Handler\Quote; 9*5c2aad12SAndreas Gohruse dokuwiki\Handler\Table; 10*5c2aad12SAndreas Gohr 1152fe2bfbSChris Smithif (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL', "\n"); // add this to make handling test cases simpler 12a9c1d2d2SChris Smith 130cecf9d5Sandiclass Doku_Handler { 140cecf9d5Sandi 150ea51e63SMatt Perry var $Renderer = null; 160cecf9d5Sandi 170ea51e63SMatt Perry var $CallWriter = null; 180cecf9d5Sandi 190cecf9d5Sandi var $calls = array(); 200cecf9d5Sandi 21e1c10e4dSchris var $status = array( 2244881bd0Shenning.noren 'section' => false, 23e950d12fSChristopher Smith 'doublequote' => 0, 240cecf9d5Sandi ); 250cecf9d5Sandi 2644881bd0Shenning.noren var $rewriteBlocks = true; 27b7c441b9SHarry Fuecks 2826e22ab8SChristopher Smith function __construct() { 29*5c2aad12SAndreas Gohr $this->CallWriter = new CallWriter($this); 300cecf9d5Sandi } 310cecf9d5Sandi 32276820f7SScrutinizer Auto-Fixer /** 33276820f7SScrutinizer Auto-Fixer * @param string $handler 34f50a239bSTakamura * @param mixed $args 35f50a239bSTakamura * @param integer|string $pos 36276820f7SScrutinizer Auto-Fixer */ 37433bef32Sandi function _addCall($handler, $args, $pos) { 380cecf9d5Sandi $call = array($handler,$args, $pos); 390cecf9d5Sandi $this->CallWriter->writeCall($call); 400cecf9d5Sandi } 410cecf9d5Sandi 4282d61635Spierre.spring function addPluginCall($plugin, $args, $state, $pos, $match) { 4382d61635Spierre.spring $call = array('plugin',array($plugin, $args, $state, $match), $pos); 4404ebd214Schris $this->CallWriter->writeCall($call); 4504ebd214Schris } 4604ebd214Schris 47433bef32Sandi function _finalize(){ 48e1c10e4dSchris 49f4f02a0fSchris $this->CallWriter->finalise(); 50f4f02a0fSchris 51e1c10e4dSchris if ( $this->status['section'] ) { 52e1c10e4dSchris $last_call = end($this->calls); 53e1c10e4dSchris array_push($this->calls,array('section_close',array(), $last_call[2])); 540cecf9d5Sandi } 550cecf9d5Sandi 56b7c441b9SHarry Fuecks if ( $this->rewriteBlocks ) { 57*5c2aad12SAndreas Gohr $B = new Block(); 580cecf9d5Sandi $this->calls = $B->process($this->calls); 59b7c441b9SHarry Fuecks } 60e0ad864eSchris 6124bb549bSchris trigger_event('PARSER_HANDLER_DONE',$this); 620cecf9d5Sandi 630cecf9d5Sandi array_unshift($this->calls,array('document_start',array(),0)); 640cecf9d5Sandi $last_call = end($this->calls); 650cecf9d5Sandi array_push($this->calls,array('document_end',array(),$last_call[2])); 660cecf9d5Sandi } 670cecf9d5Sandi 689e491c01SAndreas Gohr /** 699e491c01SAndreas Gohr * fetch the current call and advance the pointer to the next one 709e491c01SAndreas Gohr * 719e491c01SAndreas Gohr * @return bool|mixed 729e491c01SAndreas Gohr */ 730cecf9d5Sandi function fetch() { 749e491c01SAndreas Gohr $call = current($this->calls); 759e491c01SAndreas Gohr if($call !== false) { 769e491c01SAndreas Gohr next($this->calls); //advance the pointer 779e491c01SAndreas Gohr return $call; 780cecf9d5Sandi } 7944881bd0Shenning.noren return false; 800cecf9d5Sandi } 81ee20e7d1Sandi 82ee20e7d1Sandi 83ee20e7d1Sandi /** 84ee20e7d1Sandi * Special plugin handler 85ee20e7d1Sandi * 86ee20e7d1Sandi * This handler is called for all modes starting with 'plugin_'. 87ee20e7d1Sandi * An additional parameter with the plugin name is passed 88ee20e7d1Sandi * 89ee20e7d1Sandi * @author Andreas Gohr <andi@splitbrain.org> 90f50a239bSTakamura * 91f50a239bSTakamura * @param string|integer $match 92f50a239bSTakamura * @param string|integer $state 93f50a239bSTakamura * @param integer $pos 94f50a239bSTakamura * @param $pluginname 95f50a239bSTakamura * 96f50a239bSTakamura * @return bool 97ee20e7d1Sandi */ 98ee20e7d1Sandi function plugin($match, $state, $pos, $pluginname){ 99ee20e7d1Sandi $data = array($match); 10051a883edSGerrit Uitslag /** @var DokuWiki_Syntax_Plugin $plugin */ 10145d5ad75SGerrit Uitslag $plugin = plugin_load('syntax',$pluginname); 102a46d0d65SAndreas Gohr if($plugin != null){ 103f02a7d06Schris $data = $plugin->handle($match, $state, $pos, $this); 104ee20e7d1Sandi } 10513ecfb18SChris Smith if ($data !== false) { 10682d61635Spierre.spring $this->addPluginCall($pluginname,$data,$state,$pos,$match); 10713ecfb18SChris Smith } 10844881bd0Shenning.noren return true; 109ee20e7d1Sandi } 1100cecf9d5Sandi 1110cecf9d5Sandi function base($match, $state, $pos) { 1120cecf9d5Sandi switch ( $state ) { 1130cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 114433bef32Sandi $this->_addCall('cdata',array($match), $pos); 11544881bd0Shenning.noren return true; 1160cecf9d5Sandi break; 1170cecf9d5Sandi } 1180cecf9d5Sandi } 1190cecf9d5Sandi 1200cecf9d5Sandi function header($match, $state, $pos) { 121d7e8115fSAndreas Gohr // get level and title 122a4a2d4cfSAndreas Gohr $title = trim($match); 123a4a2d4cfSAndreas Gohr $level = 7 - strspn($title,'='); 124d7e8115fSAndreas Gohr if($level < 1) $level = 1; 125a4a2d4cfSAndreas Gohr $title = trim($title,'='); 126a4a2d4cfSAndreas Gohr $title = trim($title); 1270cecf9d5Sandi 128e1c10e4dSchris if ($this->status['section']) $this->_addCall('section_close',array(),$pos); 129e1c10e4dSchris 130433bef32Sandi $this->_addCall('header',array($title,$level,$pos), $pos); 131e1c10e4dSchris 132e1c10e4dSchris $this->_addCall('section_open',array($level),$pos); 13344881bd0Shenning.noren $this->status['section'] = true; 13444881bd0Shenning.noren return true; 1350cecf9d5Sandi } 1360cecf9d5Sandi 1370cecf9d5Sandi function notoc($match, $state, $pos) { 138e41c4da9SAndreas Gohr $this->_addCall('notoc',array(),$pos); 13944881bd0Shenning.noren return true; 1400cecf9d5Sandi } 1410cecf9d5Sandi 1429dc2c2afSandi function nocache($match, $state, $pos) { 1439dc2c2afSandi $this->_addCall('nocache',array(),$pos); 14444881bd0Shenning.noren return true; 1459dc2c2afSandi } 1469dc2c2afSandi 1470cecf9d5Sandi function linebreak($match, $state, $pos) { 148433bef32Sandi $this->_addCall('linebreak',array(),$pos); 14944881bd0Shenning.noren return true; 1500cecf9d5Sandi } 1510cecf9d5Sandi 1520cecf9d5Sandi function eol($match, $state, $pos) { 153433bef32Sandi $this->_addCall('eol',array(),$pos); 15444881bd0Shenning.noren return true; 1550cecf9d5Sandi } 1560cecf9d5Sandi 1570cecf9d5Sandi function hr($match, $state, $pos) { 158433bef32Sandi $this->_addCall('hr',array(),$pos); 15944881bd0Shenning.noren return true; 1600cecf9d5Sandi } 1610cecf9d5Sandi 162276820f7SScrutinizer Auto-Fixer /** 163f50a239bSTakamura * @param string|integer $match 164f50a239bSTakamura * @param string|integer $state 165f50a239bSTakamura * @param integer $pos 166276820f7SScrutinizer Auto-Fixer * @param string $name 167276820f7SScrutinizer Auto-Fixer */ 168433bef32Sandi function _nestingTag($match, $state, $pos, $name) { 1690cecf9d5Sandi switch ( $state ) { 1700cecf9d5Sandi case DOKU_LEXER_ENTER: 171433bef32Sandi $this->_addCall($name.'_open', array(), $pos); 1720cecf9d5Sandi break; 1730cecf9d5Sandi case DOKU_LEXER_EXIT: 174433bef32Sandi $this->_addCall($name.'_close', array(), $pos); 1750cecf9d5Sandi break; 1760cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 177433bef32Sandi $this->_addCall('cdata',array($match), $pos); 1780cecf9d5Sandi break; 1790cecf9d5Sandi } 1800cecf9d5Sandi } 1810cecf9d5Sandi 1820cecf9d5Sandi function strong($match, $state, $pos) { 183433bef32Sandi $this->_nestingTag($match, $state, $pos, 'strong'); 18444881bd0Shenning.noren return true; 1850cecf9d5Sandi } 1860cecf9d5Sandi 1870cecf9d5Sandi function emphasis($match, $state, $pos) { 188433bef32Sandi $this->_nestingTag($match, $state, $pos, 'emphasis'); 18944881bd0Shenning.noren return true; 1900cecf9d5Sandi } 1910cecf9d5Sandi 1920cecf9d5Sandi function underline($match, $state, $pos) { 193433bef32Sandi $this->_nestingTag($match, $state, $pos, 'underline'); 19444881bd0Shenning.noren return true; 1950cecf9d5Sandi } 1960cecf9d5Sandi 1970cecf9d5Sandi function monospace($match, $state, $pos) { 198433bef32Sandi $this->_nestingTag($match, $state, $pos, 'monospace'); 19944881bd0Shenning.noren return true; 2000cecf9d5Sandi } 2010cecf9d5Sandi 2020cecf9d5Sandi function subscript($match, $state, $pos) { 203433bef32Sandi $this->_nestingTag($match, $state, $pos, 'subscript'); 20444881bd0Shenning.noren return true; 2050cecf9d5Sandi } 2060cecf9d5Sandi 2070cecf9d5Sandi function superscript($match, $state, $pos) { 208433bef32Sandi $this->_nestingTag($match, $state, $pos, 'superscript'); 20944881bd0Shenning.noren return true; 2100cecf9d5Sandi } 2110cecf9d5Sandi 2120cecf9d5Sandi function deleted($match, $state, $pos) { 213433bef32Sandi $this->_nestingTag($match, $state, $pos, 'deleted'); 21444881bd0Shenning.noren return true; 2150cecf9d5Sandi } 2160cecf9d5Sandi 2170cecf9d5Sandi 2180cecf9d5Sandi function footnote($match, $state, $pos) { 219742c66f8Schris if (!isset($this->_footnote)) $this->_footnote = false; 2202fe7363dSchris 2215587e44cSchris switch ( $state ) { 2225587e44cSchris case DOKU_LEXER_ENTER: 2232fe7363dSchris // footnotes can not be nested - however due to limitations in lexer it can't be prevented 2242fe7363dSchris // we will still enter a new footnote mode, we just do nothing 225742c66f8Schris if ($this->_footnote) { 2262fe7363dSchris $this->_addCall('cdata',array($match), $pos); 2272fe7363dSchris break; 2282fe7363dSchris } 229742c66f8Schris $this->_footnote = true; 2302fe7363dSchris 231*5c2aad12SAndreas Gohr $this->CallWriter = new Nest($this->CallWriter,'footnote_close'); 2324a26ad85Schris $this->_addCall('footnote_open', array(), $pos); 2335587e44cSchris break; 2345587e44cSchris case DOKU_LEXER_EXIT: 2352fe7363dSchris // check whether we have already exitted the footnote mode, can happen if the modes were nested 236742c66f8Schris if (!$this->_footnote) { 2372fe7363dSchris $this->_addCall('cdata',array($match), $pos); 2382fe7363dSchris break; 2392fe7363dSchris } 2402fe7363dSchris 241742c66f8Schris $this->_footnote = false; 2425587e44cSchris $this->_addCall('footnote_close', array(), $pos); 243*5c2aad12SAndreas Gohr 244*5c2aad12SAndreas Gohr /** @var Nest $reWriter */ 245*5c2aad12SAndreas Gohr $reWriter = $this->CallWriter; 246*5c2aad12SAndreas Gohr $this->CallWriter = $reWriter->process(); 2475587e44cSchris break; 2485587e44cSchris case DOKU_LEXER_UNMATCHED: 2495587e44cSchris $this->_addCall('cdata', array($match), $pos); 2505587e44cSchris break; 2515587e44cSchris } 25244881bd0Shenning.noren return true; 2530cecf9d5Sandi } 2540cecf9d5Sandi 2550cecf9d5Sandi function listblock($match, $state, $pos) { 2560cecf9d5Sandi switch ( $state ) { 2570cecf9d5Sandi case DOKU_LEXER_ENTER: 258*5c2aad12SAndreas Gohr $this->CallWriter = new Lists($this->CallWriter); 259433bef32Sandi $this->_addCall('list_open', array($match), $pos); 2600cecf9d5Sandi break; 2610cecf9d5Sandi case DOKU_LEXER_EXIT: 262433bef32Sandi $this->_addCall('list_close', array(), $pos); 263*5c2aad12SAndreas Gohr /** @var Lists $reWriter */ 264*5c2aad12SAndreas Gohr $reWriter = $this->CallWriter; 265*5c2aad12SAndreas Gohr $this->CallWriter = $reWriter->process(); 2660cecf9d5Sandi break; 2670cecf9d5Sandi case DOKU_LEXER_MATCHED: 268433bef32Sandi $this->_addCall('list_item', array($match), $pos); 2690cecf9d5Sandi break; 2700cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 271433bef32Sandi $this->_addCall('cdata', array($match), $pos); 2720cecf9d5Sandi break; 2730cecf9d5Sandi } 27444881bd0Shenning.noren return true; 2750cecf9d5Sandi } 2760cecf9d5Sandi 2770cecf9d5Sandi function unformatted($match, $state, $pos) { 2780cecf9d5Sandi if ( $state == DOKU_LEXER_UNMATCHED ) { 279433bef32Sandi $this->_addCall('unformatted',array($match), $pos); 2800cecf9d5Sandi } 28144881bd0Shenning.noren return true; 2820cecf9d5Sandi } 2830cecf9d5Sandi 2840cecf9d5Sandi function php($match, $state, $pos) { 285df9add72Schris global $conf; 2860cecf9d5Sandi if ( $state == DOKU_LEXER_UNMATCHED ) { 287433bef32Sandi $this->_addCall('php',array($match), $pos); 2880cecf9d5Sandi } 28944881bd0Shenning.noren return true; 2900cecf9d5Sandi } 2910cecf9d5Sandi 29207f89c3cSAnika Henke function phpblock($match, $state, $pos) { 29307f89c3cSAnika Henke global $conf; 29407f89c3cSAnika Henke if ( $state == DOKU_LEXER_UNMATCHED ) { 29507f89c3cSAnika Henke $this->_addCall('phpblock',array($match), $pos); 29607f89c3cSAnika Henke } 29707f89c3cSAnika Henke return true; 29807f89c3cSAnika Henke } 29907f89c3cSAnika Henke 3000cecf9d5Sandi function html($match, $state, $pos) { 301df9add72Schris global $conf; 3020cecf9d5Sandi if ( $state == DOKU_LEXER_UNMATCHED ) { 303433bef32Sandi $this->_addCall('html',array($match), $pos); 3040cecf9d5Sandi } 30544881bd0Shenning.noren return true; 3060cecf9d5Sandi } 3070cecf9d5Sandi 30807f89c3cSAnika Henke function htmlblock($match, $state, $pos) { 30907f89c3cSAnika Henke global $conf; 31007f89c3cSAnika Henke if ( $state == DOKU_LEXER_UNMATCHED ) { 31107f89c3cSAnika Henke $this->_addCall('htmlblock',array($match), $pos); 31207f89c3cSAnika Henke } 31307f89c3cSAnika Henke return true; 31407f89c3cSAnika Henke } 31507f89c3cSAnika Henke 3160cecf9d5Sandi function preformatted($match, $state, $pos) { 3170cecf9d5Sandi switch ( $state ) { 3180cecf9d5Sandi case DOKU_LEXER_ENTER: 319*5c2aad12SAndreas Gohr $this->CallWriter = new Preformatted($this->CallWriter); 320433bef32Sandi $this->_addCall('preformatted_start',array(), $pos); 3210cecf9d5Sandi break; 3220cecf9d5Sandi case DOKU_LEXER_EXIT: 323433bef32Sandi $this->_addCall('preformatted_end',array(), $pos); 324*5c2aad12SAndreas Gohr /** @var Preformatted $reWriter */ 325*5c2aad12SAndreas Gohr $reWriter = $this->CallWriter; 326*5c2aad12SAndreas Gohr $this->CallWriter = $reWriter->process(); 3270cecf9d5Sandi break; 3280cecf9d5Sandi case DOKU_LEXER_MATCHED: 329433bef32Sandi $this->_addCall('preformatted_newline',array(), $pos); 3300cecf9d5Sandi break; 3310cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 332433bef32Sandi $this->_addCall('preformatted_content',array($match), $pos); 3330cecf9d5Sandi break; 3340cecf9d5Sandi } 3350cecf9d5Sandi 33644881bd0Shenning.noren return true; 3370cecf9d5Sandi } 3380cecf9d5Sandi 3390cecf9d5Sandi function quote($match, $state, $pos) { 3400cecf9d5Sandi 3410cecf9d5Sandi switch ( $state ) { 3420cecf9d5Sandi 3430cecf9d5Sandi case DOKU_LEXER_ENTER: 344*5c2aad12SAndreas Gohr $this->CallWriter = new Quote($this->CallWriter); 345433bef32Sandi $this->_addCall('quote_start',array($match), $pos); 3460cecf9d5Sandi break; 3470cecf9d5Sandi 3480cecf9d5Sandi case DOKU_LEXER_EXIT: 349433bef32Sandi $this->_addCall('quote_end',array(), $pos); 350*5c2aad12SAndreas Gohr /** @var Lists $reWriter */ 351*5c2aad12SAndreas Gohr $reWriter = $this->CallWriter; 352*5c2aad12SAndreas Gohr $this->CallWriter = $reWriter->process(); 3530cecf9d5Sandi break; 3540cecf9d5Sandi 3550cecf9d5Sandi case DOKU_LEXER_MATCHED: 356433bef32Sandi $this->_addCall('quote_newline',array($match), $pos); 3570cecf9d5Sandi break; 3580cecf9d5Sandi 3590cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 360433bef32Sandi $this->_addCall('cdata',array($match), $pos); 3610cecf9d5Sandi break; 3620cecf9d5Sandi 3630cecf9d5Sandi } 3640cecf9d5Sandi 36544881bd0Shenning.noren return true; 3660cecf9d5Sandi } 3670cecf9d5Sandi 368e2d88156SLarsDW223 /** 369e2d88156SLarsDW223 * Internal function for parsing highlight options. 370e2d88156SLarsDW223 * $options is parsed for key value pairs separated by commas. 371e2d88156SLarsDW223 * A value might also be missing in which case the value will simple 372e2d88156SLarsDW223 * be set to true. Commas in strings are ignored, e.g. option="4,56" 373e2d88156SLarsDW223 * will work as expected and will only create one entry. 374e2d88156SLarsDW223 * 37554f741e8SAndreas Gohr * @param string $options space separated list of key-value pairs, 376e2d88156SLarsDW223 * e.g. option1=123, option2="456" 377e2d88156SLarsDW223 * @return array|null Array of key-value pairs $array['key'] = 'value'; 378e2d88156SLarsDW223 * or null if no entries found 379e2d88156SLarsDW223 */ 380e2d88156SLarsDW223 protected function parse_highlight_options ($options) { 381e2d88156SLarsDW223 $result = array(); 38254f741e8SAndreas Gohr preg_match_all('/(\w+(?:="[^"]*"))|(\w+(?:=[^\s]*))|(\w+[^=\s\]])(?:\s*)/', $options, $matches, PREG_SET_ORDER); 383e2d88156SLarsDW223 foreach ($matches as $match) { 384e2d88156SLarsDW223 $equal_sign = strpos($match [0], '='); 385e2d88156SLarsDW223 if ($equal_sign === false) { 38654f741e8SAndreas Gohr $key = trim($match[0]); 387e2d88156SLarsDW223 $result [$key] = 1; 388e2d88156SLarsDW223 } else { 389e2d88156SLarsDW223 $key = substr($match[0], 0, $equal_sign); 390e2d88156SLarsDW223 $value = substr($match[0], $equal_sign+1); 391e2d88156SLarsDW223 $value = trim($value, '"'); 392e2d88156SLarsDW223 if (strlen($value) > 0) { 393e2d88156SLarsDW223 $result [$key] = $value; 394e2d88156SLarsDW223 } else { 395e2d88156SLarsDW223 $result [$key] = 1; 396e2d88156SLarsDW223 } 397e2d88156SLarsDW223 } 398e2d88156SLarsDW223 } 399e2d88156SLarsDW223 400e2d88156SLarsDW223 // Check for supported options 401e2d88156SLarsDW223 $result = array_intersect_key( 402e2d88156SLarsDW223 $result, 403e2d88156SLarsDW223 array_flip(array( 404e2d88156SLarsDW223 'enable_line_numbers', 405e2d88156SLarsDW223 'start_line_numbers_at', 406e2d88156SLarsDW223 'highlight_lines_extra', 407e2d88156SLarsDW223 'enable_keyword_links') 408e2d88156SLarsDW223 ) 409e2d88156SLarsDW223 ); 410e2d88156SLarsDW223 411e2d88156SLarsDW223 // Sanitize values 412e2d88156SLarsDW223 if(isset($result['enable_line_numbers'])) { 41354f741e8SAndreas Gohr if($result['enable_line_numbers'] === 'false') { 41454f741e8SAndreas Gohr $result['enable_line_numbers'] = false; 41554f741e8SAndreas Gohr } 416e2d88156SLarsDW223 $result['enable_line_numbers'] = (bool) $result['enable_line_numbers']; 417e2d88156SLarsDW223 } 418e2d88156SLarsDW223 if(isset($result['highlight_lines_extra'])) { 419e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_map('intval', explode(',', $result['highlight_lines_extra'])); 420e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_filter($result['highlight_lines_extra']); 421e2d88156SLarsDW223 $result['highlight_lines_extra'] = array_unique($result['highlight_lines_extra']); 422e2d88156SLarsDW223 } 423e2d88156SLarsDW223 if(isset($result['start_line_numbers_at'])) { 424e2d88156SLarsDW223 $result['start_line_numbers_at'] = (int) $result['start_line_numbers_at']; 425e2d88156SLarsDW223 } 426e2d88156SLarsDW223 if(isset($result['enable_keyword_links'])) { 42754f741e8SAndreas Gohr if($result['enable_keyword_links'] === 'false') { 42854f741e8SAndreas Gohr $result['enable_keyword_links'] = false; 42954f741e8SAndreas Gohr } 43054f741e8SAndreas Gohr $result['enable_keyword_links'] = (bool) $result['enable_keyword_links']; 431e2d88156SLarsDW223 } 432e2d88156SLarsDW223 if (count($result) == 0) { 433e2d88156SLarsDW223 return null; 434e2d88156SLarsDW223 } 435e2d88156SLarsDW223 436e2d88156SLarsDW223 return $result; 437e2d88156SLarsDW223 } 438e2d88156SLarsDW223 4393d491f75SAndreas Gohr function file($match, $state, $pos) { 4403d491f75SAndreas Gohr return $this->code($match, $state, $pos, 'file'); 4413d491f75SAndreas Gohr } 4423d491f75SAndreas Gohr 4433d491f75SAndreas Gohr function code($match, $state, $pos, $type='code') { 4443d491f75SAndreas Gohr if ( $state == DOKU_LEXER_UNMATCHED ) { 4454b7f9e70STom N Harris $matches = explode('>',$match,2); 446e2d88156SLarsDW223 // Cut out variable options enclosed in [] 447e2d88156SLarsDW223 preg_match('/\[.*\]/', $matches[0], $options); 448e2d88156SLarsDW223 if (!empty($options[0])) { 449e2d88156SLarsDW223 $matches[0] = str_replace($options[0], '', $matches[0]); 450e2d88156SLarsDW223 } 4510139312bSAdrian Lang $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY); 4520139312bSAdrian Lang while(count($param) < 2) array_push($param, null); 4530139312bSAdrian Lang // We shortcut html here. 4540139312bSAdrian Lang if ($param[0] == 'html') $param[0] = 'html4strict'; 4550139312bSAdrian Lang if ($param[0] == '-') $param[0] = null; 4560139312bSAdrian Lang array_unshift($param, $matches[1]); 457e2d88156SLarsDW223 if (!empty($options[0])) { 458e2d88156SLarsDW223 $param [] = $this->parse_highlight_options ($options[0]); 459e2d88156SLarsDW223 } 4600139312bSAdrian Lang $this->_addCall($type, $param, $pos); 4610cecf9d5Sandi } 46244881bd0Shenning.noren return true; 4630cecf9d5Sandi } 4640cecf9d5Sandi 4650cecf9d5Sandi function acronym($match, $state, $pos) { 466433bef32Sandi $this->_addCall('acronym',array($match), $pos); 46744881bd0Shenning.noren return true; 4680cecf9d5Sandi } 4690cecf9d5Sandi 4700cecf9d5Sandi function smiley($match, $state, $pos) { 471433bef32Sandi $this->_addCall('smiley',array($match), $pos); 47244881bd0Shenning.noren return true; 4730cecf9d5Sandi } 4740cecf9d5Sandi 4750cecf9d5Sandi function wordblock($match, $state, $pos) { 476433bef32Sandi $this->_addCall('wordblock',array($match), $pos); 47744881bd0Shenning.noren return true; 4780cecf9d5Sandi } 4790cecf9d5Sandi 4800cecf9d5Sandi function entity($match, $state, $pos) { 481433bef32Sandi $this->_addCall('entity',array($match), $pos); 48244881bd0Shenning.noren return true; 4830cecf9d5Sandi } 4840cecf9d5Sandi 4850cecf9d5Sandi function multiplyentity($match, $state, $pos) { 4860cecf9d5Sandi preg_match_all('/\d+/',$match,$matches); 487433bef32Sandi $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos); 48844881bd0Shenning.noren return true; 4890cecf9d5Sandi } 4900cecf9d5Sandi 4910cecf9d5Sandi function singlequoteopening($match, $state, $pos) { 492433bef32Sandi $this->_addCall('singlequoteopening',array(), $pos); 49344881bd0Shenning.noren return true; 4940cecf9d5Sandi } 4950cecf9d5Sandi 4960cecf9d5Sandi function singlequoteclosing($match, $state, $pos) { 497433bef32Sandi $this->_addCall('singlequoteclosing',array(), $pos); 49844881bd0Shenning.noren return true; 4990cecf9d5Sandi } 5000cecf9d5Sandi 50157d757d1SAndreas Gohr function apostrophe($match, $state, $pos) { 50257d757d1SAndreas Gohr $this->_addCall('apostrophe',array(), $pos); 50357d757d1SAndreas Gohr return true; 50457d757d1SAndreas Gohr } 50557d757d1SAndreas Gohr 5060cecf9d5Sandi function doublequoteopening($match, $state, $pos) { 507433bef32Sandi $this->_addCall('doublequoteopening',array(), $pos); 508e950d12fSChristopher Smith $this->status['doublequote']++; 50944881bd0Shenning.noren return true; 5100cecf9d5Sandi } 5110cecf9d5Sandi 5120cecf9d5Sandi function doublequoteclosing($match, $state, $pos) { 513e950d12fSChristopher Smith if ($this->status['doublequote'] <= 0) { 514e950d12fSChristopher Smith $this->doublequoteopening($match, $state, $pos); 515e950d12fSChristopher Smith } else { 516433bef32Sandi $this->_addCall('doublequoteclosing',array(), $pos); 517e950d12fSChristopher Smith $this->status['doublequote'] = max(0, --$this->status['doublequote']); 518e950d12fSChristopher Smith } 51944881bd0Shenning.noren return true; 5200cecf9d5Sandi } 5210cecf9d5Sandi 5220cecf9d5Sandi function camelcaselink($match, $state, $pos) { 523433bef32Sandi $this->_addCall('camelcaselink',array($match), $pos); 52444881bd0Shenning.noren return true; 5250cecf9d5Sandi } 5260cecf9d5Sandi 5270cecf9d5Sandi /* 5280cecf9d5Sandi */ 5290cecf9d5Sandi function internallink($match, $state, $pos) { 5300cecf9d5Sandi // Strip the opening and closing markup 5310cecf9d5Sandi $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match); 5320cecf9d5Sandi 5330cecf9d5Sandi // Split title from URL 5344b7f9e70STom N Harris $link = explode('|',$link,2); 5350cecf9d5Sandi if ( !isset($link[1]) ) { 5360ea51e63SMatt Perry $link[1] = null; 5370cecf9d5Sandi } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) { 5385578eb8fSandi // If the title is an image, convert it to an array containing the image details 539b625487dSandi $link[1] = Doku_Handler_Parse_Media($link[1]); 5400cecf9d5Sandi } 5410b7c14c2Sandi $link[0] = trim($link[0]); 5420cecf9d5Sandi 5430e1c636eSandi //decide which kind of link it is 5440e1c636eSandi 5456efc45a2SDmitry Katsubo if ( link_isinterwiki($link[0]) ) { 5460e1c636eSandi // Interwiki 5474b7f9e70STom N Harris $interwiki = explode('>',$link[0],2); 548433bef32Sandi $this->_addCall( 5490cecf9d5Sandi 'interwikilink', 5500cecf9d5Sandi array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]), 5510cecf9d5Sandi $pos 5520cecf9d5Sandi ); 55315f1b77cSAndreas Gohr }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) { 5540e1c636eSandi // Windows Share 555433bef32Sandi $this->_addCall( 5560cecf9d5Sandi 'windowssharelink', 5570cecf9d5Sandi array($link[0],$link[1]), 5580cecf9d5Sandi $pos 5590cecf9d5Sandi ); 5604468cb4cSAndreas Gohr }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) { 5610e1c636eSandi // external link (accepts all protocols) 562433bef32Sandi $this->_addCall( 5630cecf9d5Sandi 'externallink', 5640cecf9d5Sandi array($link[0],$link[1]), 5650cecf9d5Sandi $pos 5660cecf9d5Sandi ); 5670a1d30bfSchris }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) { 5680a1d30bfSchris // E-Mail (pattern above is defined in inc/mail.php) 569a6755281Sandi $this->_addCall( 570a6755281Sandi 'emaillink', 571a6755281Sandi array($link[0],$link[1]), 572a6755281Sandi $pos 573a6755281Sandi ); 5740b7c14c2Sandi }elseif ( preg_match('!^#.+!',$link[0]) ){ 5750b7c14c2Sandi // local link 5760b7c14c2Sandi $this->_addCall( 5770b7c14c2Sandi 'locallink', 5780b7c14c2Sandi array(substr($link[0],1),$link[1]), 5790b7c14c2Sandi $pos 5800b7c14c2Sandi ); 5810e1c636eSandi }else{ 5820e1c636eSandi // internal link 583433bef32Sandi $this->_addCall( 5840e1c636eSandi 'internallink', 5850e1c636eSandi array($link[0],$link[1]), 5860e1c636eSandi $pos 5870e1c636eSandi ); 5880cecf9d5Sandi } 5890e1c636eSandi 59044881bd0Shenning.noren return true; 5910cecf9d5Sandi } 5920cecf9d5Sandi 5930cecf9d5Sandi function filelink($match, $state, $pos) { 5940ea51e63SMatt Perry $this->_addCall('filelink',array($match, null), $pos); 59544881bd0Shenning.noren return true; 5960cecf9d5Sandi } 5970cecf9d5Sandi 5980cecf9d5Sandi function windowssharelink($match, $state, $pos) { 5990ea51e63SMatt Perry $this->_addCall('windowssharelink',array($match, null), $pos); 60044881bd0Shenning.noren return true; 6010cecf9d5Sandi } 6020cecf9d5Sandi 6030cecf9d5Sandi function media($match, $state, $pos) { 6040cecf9d5Sandi $p = Doku_Handler_Parse_Media($match); 6050cecf9d5Sandi 606433bef32Sandi $this->_addCall( 6070cecf9d5Sandi $p['type'], 608dc673a5bSjoe.lapp array($p['src'], $p['title'], $p['align'], $p['width'], 609dc673a5bSjoe.lapp $p['height'], $p['cache'], $p['linking']), 6100cecf9d5Sandi $pos 6110cecf9d5Sandi ); 61244881bd0Shenning.noren return true; 6130cecf9d5Sandi } 6140cecf9d5Sandi 615b625487dSandi function rss($match, $state, $pos) { 616b625487dSandi $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match); 6173db95becSAndreas Gohr 6183db95becSAndreas Gohr // get params 6193db95becSAndreas Gohr list($link,$params) = explode(' ',$link,2); 6203db95becSAndreas Gohr 6213db95becSAndreas Gohr $p = array(); 6223db95becSAndreas Gohr if(preg_match('/\b(\d+)\b/',$params,$match)){ 6233db95becSAndreas Gohr $p['max'] = $match[1]; 6243db95becSAndreas Gohr }else{ 6253db95becSAndreas Gohr $p['max'] = 8; 6263db95becSAndreas Gohr } 6273db95becSAndreas Gohr $p['reverse'] = (preg_match('/rev/',$params)); 6283db95becSAndreas Gohr $p['author'] = (preg_match('/\b(by|author)/',$params)); 6293db95becSAndreas Gohr $p['date'] = (preg_match('/\b(date)/',$params)); 6303db95becSAndreas Gohr $p['details'] = (preg_match('/\b(desc|detail)/',$params)); 63138c6f603SRobin H. Johnson $p['nosort'] = (preg_match('/\b(nosort)\b/',$params)); 6323db95becSAndreas Gohr 6330a69dff7Schris if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) { 6340a69dff7Schris $period = array('d' => 86400, 'h' => 3600, 'm' => 60); 6350a69dff7Schris $p['refresh'] = max(600,$match[1]*$period[$match[2]]); // n * period in seconds, minimum 10 minutes 6360a69dff7Schris } else { 6370a69dff7Schris $p['refresh'] = 14400; // default to 4 hours 6380a69dff7Schris } 6390a69dff7Schris 6403db95becSAndreas Gohr $this->_addCall('rss',array($link,$p),$pos); 64144881bd0Shenning.noren return true; 642b625487dSandi } 643b625487dSandi 6440cecf9d5Sandi function externallink($match, $state, $pos) { 645da9f31c5SAndreas Gohr $url = $match; 646da9f31c5SAndreas Gohr $title = null; 6470cecf9d5Sandi 648da9f31c5SAndreas Gohr // add protocol on simple short URLs 649da9f31c5SAndreas Gohr if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){ 650da9f31c5SAndreas Gohr $title = $url; 651da9f31c5SAndreas Gohr $url = 'ftp://'.$url; 652da9f31c5SAndreas Gohr } 653da9f31c5SAndreas Gohr if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){ 654da9f31c5SAndreas Gohr $title = $url; 655da9f31c5SAndreas Gohr $url = 'http://'.$url; 656da9f31c5SAndreas Gohr } 657da9f31c5SAndreas Gohr 658da9f31c5SAndreas Gohr $this->_addCall('externallink',array($url, $title), $pos); 65944881bd0Shenning.noren return true; 6600cecf9d5Sandi } 6610cecf9d5Sandi 66271352defSandi function emaillink($match, $state, $pos) { 6630cecf9d5Sandi $email = preg_replace(array('/^</','/>$/'),'',$match); 6640ea51e63SMatt Perry $this->_addCall('emaillink',array($email, null), $pos); 66544881bd0Shenning.noren return true; 6660cecf9d5Sandi } 6670cecf9d5Sandi 6680cecf9d5Sandi function table($match, $state, $pos) { 6690cecf9d5Sandi switch ( $state ) { 6700cecf9d5Sandi 6710cecf9d5Sandi case DOKU_LEXER_ENTER: 6720cecf9d5Sandi 673*5c2aad12SAndreas Gohr $this->CallWriter = new Table($this->CallWriter); 6740cecf9d5Sandi 67590df9a4dSAdrian Lang $this->_addCall('table_start', array($pos + 1), $pos); 6760cecf9d5Sandi if ( trim($match) == '^' ) { 677433bef32Sandi $this->_addCall('tableheader', array(), $pos); 6780cecf9d5Sandi } else { 679433bef32Sandi $this->_addCall('tablecell', array(), $pos); 6800cecf9d5Sandi } 6810cecf9d5Sandi break; 6820cecf9d5Sandi 6830cecf9d5Sandi case DOKU_LEXER_EXIT: 68490df9a4dSAdrian Lang $this->_addCall('table_end', array($pos), $pos); 685*5c2aad12SAndreas Gohr /** @var Table $reWriter */ 686*5c2aad12SAndreas Gohr $reWriter = $this->CallWriter; 687*5c2aad12SAndreas Gohr $this->CallWriter = $reWriter->process(); 6880cecf9d5Sandi break; 6890cecf9d5Sandi 6900cecf9d5Sandi case DOKU_LEXER_UNMATCHED: 6910cecf9d5Sandi if ( trim($match) != '' ) { 692433bef32Sandi $this->_addCall('cdata',array($match), $pos); 6930cecf9d5Sandi } 6940cecf9d5Sandi break; 6950cecf9d5Sandi 6960cecf9d5Sandi case DOKU_LEXER_MATCHED: 6979ab75d9eSAndreas Gohr if ( $match == ' ' ){ 6989ab75d9eSAndreas Gohr $this->_addCall('cdata', array($match), $pos); 69925b97867Shakan.sandell } else if ( preg_match('/:::/',$match) ) { 70025b97867Shakan.sandell $this->_addCall('rowspan', array($match), $pos); 701e205b721SAndreas Gohr } else if ( preg_match('/\t+/',$match) ) { 7029ab75d9eSAndreas Gohr $this->_addCall('table_align', array($match), $pos); 703e205b721SAndreas Gohr } else if ( preg_match('/ {2,}/',$match) ) { 704433bef32Sandi $this->_addCall('table_align', array($match), $pos); 7050cecf9d5Sandi } else if ( $match == "\n|" ) { 706433bef32Sandi $this->_addCall('table_row', array(), $pos); 707433bef32Sandi $this->_addCall('tablecell', array(), $pos); 7080cecf9d5Sandi } else if ( $match == "\n^" ) { 709433bef32Sandi $this->_addCall('table_row', array(), $pos); 710433bef32Sandi $this->_addCall('tableheader', array(), $pos); 7110cecf9d5Sandi } else if ( $match == '|' ) { 712433bef32Sandi $this->_addCall('tablecell', array(), $pos); 7130cecf9d5Sandi } else if ( $match == '^' ) { 714433bef32Sandi $this->_addCall('tableheader', array(), $pos); 7150cecf9d5Sandi } 7160cecf9d5Sandi break; 7170cecf9d5Sandi } 71844881bd0Shenning.noren return true; 7190cecf9d5Sandi } 7200cecf9d5Sandi} 7210cecf9d5Sandi 7220cecf9d5Sandi//------------------------------------------------------------------------ 7230cecf9d5Sandifunction Doku_Handler_Parse_Media($match) { 7240cecf9d5Sandi 7250cecf9d5Sandi // Strip the opening and closing markup 7260cecf9d5Sandi $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match); 7270cecf9d5Sandi 7280cecf9d5Sandi // Split title from URL 7294b7f9e70STom N Harris $link = explode('|',$link,2); 7300cecf9d5Sandi 7310cecf9d5Sandi // Check alignment 7320cecf9d5Sandi $ralign = (bool)preg_match('/^ /',$link[0]); 7330cecf9d5Sandi $lalign = (bool)preg_match('/ $/',$link[0]); 7340cecf9d5Sandi 7350cecf9d5Sandi // Logic = what's that ;)... 7360cecf9d5Sandi if ( $lalign & $ralign ) { 7370cecf9d5Sandi $align = 'center'; 7380cecf9d5Sandi } else if ( $ralign ) { 7390cecf9d5Sandi $align = 'right'; 7400cecf9d5Sandi } else if ( $lalign ) { 7410cecf9d5Sandi $align = 'left'; 7420cecf9d5Sandi } else { 7430ea51e63SMatt Perry $align = null; 7440cecf9d5Sandi } 7450cecf9d5Sandi 7460cecf9d5Sandi // The title... 7470cecf9d5Sandi if ( !isset($link[1]) ) { 7480ea51e63SMatt Perry $link[1] = null; 7490cecf9d5Sandi } 7500cecf9d5Sandi 7514826ab45Sandi //remove aligning spaces 7524826ab45Sandi $link[0] = trim($link[0]); 7530cecf9d5Sandi 7544826ab45Sandi //split into src and parameters (using the very last questionmark) 7554826ab45Sandi $pos = strrpos($link[0], '?'); 7564826ab45Sandi if($pos !== false){ 7574826ab45Sandi $src = substr($link[0],0,$pos); 7584826ab45Sandi $param = substr($link[0],$pos+1); 7590cecf9d5Sandi }else{ 7604826ab45Sandi $src = $link[0]; 7614826ab45Sandi $param = ''; 7620cecf9d5Sandi } 7630cecf9d5Sandi 7644826ab45Sandi //parse width and height 7654826ab45Sandi if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){ 766443e135dSChristopher Smith !empty($size[1]) ? $w = $size[1] : $w = null; 767443e135dSChristopher Smith !empty($size[3]) ? $h = $size[3] : $h = null; 768fc1c55b1Shfuecks } else { 7690ea51e63SMatt Perry $w = null; 7700ea51e63SMatt Perry $h = null; 7710cecf9d5Sandi } 7720cecf9d5Sandi 773dc673a5bSjoe.lapp //get linking command 774d35ab615Shenning.noren if(preg_match('/nolink/i',$param)){ 775dc673a5bSjoe.lapp $linking = 'nolink'; 776d35ab615Shenning.noren }else if(preg_match('/direct/i',$param)){ 777dc673a5bSjoe.lapp $linking = 'direct'; 7788acb3108SAndreas Gohr }else if(preg_match('/linkonly/i',$param)){ 7798acb3108SAndreas Gohr $linking = 'linkonly'; 780dc673a5bSjoe.lapp }else{ 781dc673a5bSjoe.lapp $linking = 'details'; 782dc673a5bSjoe.lapp } 783dc673a5bSjoe.lapp 7844826ab45Sandi //get caching command 7854826ab45Sandi if (preg_match('/(nocache|recache)/i',$param,$cachemode)){ 7864826ab45Sandi $cache = $cachemode[1]; 7870cecf9d5Sandi }else{ 7884826ab45Sandi $cache = 'cache'; 7890cecf9d5Sandi } 7900cecf9d5Sandi 7916efc45a2SDmitry Katsubo // Check whether this is a local or remote image or interwiki 7926efc45a2SDmitry Katsubo if (media_isexternal($src) || link_isinterwiki($src)){ 7934826ab45Sandi $call = 'externalmedia'; 7940cecf9d5Sandi } else { 7954826ab45Sandi $call = 'internalmedia'; 7960cecf9d5Sandi } 7970cecf9d5Sandi 7980cecf9d5Sandi $params = array( 7990cecf9d5Sandi 'type'=>$call, 8004826ab45Sandi 'src'=>$src, 8010cecf9d5Sandi 'title'=>$link[1], 8020cecf9d5Sandi 'align'=>$align, 8034826ab45Sandi 'width'=>$w, 8044826ab45Sandi 'height'=>$h, 8050cecf9d5Sandi 'cache'=>$cache, 806dc673a5bSjoe.lapp 'linking'=>$linking, 8070cecf9d5Sandi ); 8080cecf9d5Sandi 8090cecf9d5Sandi return $params; 8100cecf9d5Sandi} 8110cecf9d5Sandi 8129569a107SDanny Lin 8132a27e99aSandi 814e3776c06SMichael Hamann//Setup VIM: ex: et ts=4 : 815