| [ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../../').'/'); 3 4 if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL',"\n"); // add this to make handling test cases simpler 5 6 class Doku_Handler { 7 8 var $Renderer = NULL; 9 10 var $CallWriter = NULL; 11 12 var $calls = array(); 13 14 var $status = array( 15 'section' => false, 16 'section_edit_start' => -1, 17 'section_edit_level' => 1, 18 'section_edit_title' => '' 19 ); 20 21 var $rewriteBlocks = true; 22 23 function Doku_Handler() { 24 $this->CallWriter = & new Doku_Handler_CallWriter($this); 25 } 26 27 function _addCall($handler, $args, $pos) { 28 $call = array($handler,$args, $pos); 29 $this->CallWriter->writeCall($call); 30 } 31 32 function addPluginCall($plugin, $args, $state, $pos, $match) { 33 $call = array('plugin',array($plugin, $args, $state, $match), $pos); 34 $this->CallWriter->writeCall($call); 35 } 36 37 function _finalize(){ 38 39 $this->CallWriter->finalise(); 40 41 if ( $this->status['section'] ) { 42 $last_call = end($this->calls); 43 array_push($this->calls,array('section_close',array(), $last_call[2])); 44 if ($this->status['section_edit_start']>1) { 45 // ignore last edit section if there is only one header 46 array_push($this->calls,array('section_edit',array($this->status['section_edit_start'], 0, $this->status['section_edit_level'], $this->status['section_edit_title']), $last_call[2])); 47 } 48 } 49 50 if ( $this->rewriteBlocks ) { 51 $B = & new Doku_Handler_Block(); 52 $this->calls = $B->process($this->calls); 53 } 54 55 trigger_event('PARSER_HANDLER_DONE',$this); 56 57 array_unshift($this->calls,array('document_start',array(),0)); 58 $last_call = end($this->calls); 59 array_push($this->calls,array('document_end',array(),$last_call[2])); 60 } 61 62 function fetch() { 63 $call = each($this->calls); 64 if ( $call ) { 65 return $call['value']; 66 } 67 return false; 68 } 69 70 71 /** 72 * Special plugin handler 73 * 74 * This handler is called for all modes starting with 'plugin_'. 75 * An additional parameter with the plugin name is passed 76 * 77 * @author Andreas Gohr <andi@splitbrain.org> 78 */ 79 function plugin($match, $state, $pos, $pluginname){ 80 $data = array($match); 81 $plugin =& plugin_load('syntax',$pluginname); 82 if($plugin != null){ 83 $data = $plugin->handle($match, $state, $pos, $this); 84 } 85 if ($data !== false) { 86 $this->addPluginCall($pluginname,$data,$state,$pos,$match); 87 } 88 return true; 89 } 90 91 function base($match, $state, $pos) { 92 switch ( $state ) { 93 case DOKU_LEXER_UNMATCHED: 94 $this->_addCall('cdata',array($match), $pos); 95 return true; 96 break; 97 } 98 } 99 100 function header($match, $state, $pos) { 101 global $conf; 102 103 // get level and title 104 $title = trim($match); 105 $level = 7 - strspn($title,'='); 106 if($level < 1) $level = 1; 107 $title = trim($title,'='); 108 $title = trim($title); 109 110 if ($this->status['section']) $this->_addCall('section_close',array(),$pos); 111 112 if ($level<=$conf['maxseclevel']) { 113 $this->_addCall('section_edit',array($this->status['section_edit_start'], $pos-1, $this->status['section_edit_level'], $this->status['section_edit_title']), $pos); 114 $this->status['section_edit_start'] = $pos; 115 $this->status['section_edit_level'] = $level; 116 $this->status['section_edit_title'] = $title; 117 } 118 119 $this->_addCall('header',array($title,$level,$pos), $pos); 120 121 $this->_addCall('section_open',array($level),$pos); 122 $this->status['section'] = true; 123 return true; 124 } 125 126 function notoc($match, $state, $pos) { 127 $this->_addCall('notoc',array(),$pos); 128 return true; 129 } 130 131 function nocache($match, $state, $pos) { 132 $this->_addCall('nocache',array(),$pos); 133 return true; 134 } 135 136 function linebreak($match, $state, $pos) { 137 $this->_addCall('linebreak',array(),$pos); 138 return true; 139 } 140 141 function eol($match, $state, $pos) { 142 $this->_addCall('eol',array(),$pos); 143 return true; 144 } 145 146 function hr($match, $state, $pos) { 147 $this->_addCall('hr',array(),$pos); 148 return true; 149 } 150 151 function _nestingTag($match, $state, $pos, $name) { 152 switch ( $state ) { 153 case DOKU_LEXER_ENTER: 154 $this->_addCall($name.'_open', array(), $pos); 155 break; 156 case DOKU_LEXER_EXIT: 157 $this->_addCall($name.'_close', array(), $pos); 158 break; 159 case DOKU_LEXER_UNMATCHED: 160 $this->_addCall('cdata',array($match), $pos); 161 break; 162 } 163 } 164 165 function strong($match, $state, $pos) { 166 $this->_nestingTag($match, $state, $pos, 'strong'); 167 return true; 168 } 169 170 function emphasis($match, $state, $pos) { 171 $this->_nestingTag($match, $state, $pos, 'emphasis'); 172 return true; 173 } 174 175 function underline($match, $state, $pos) { 176 $this->_nestingTag($match, $state, $pos, 'underline'); 177 return true; 178 } 179 180 function monospace($match, $state, $pos) { 181 $this->_nestingTag($match, $state, $pos, 'monospace'); 182 return true; 183 } 184 185 function subscript($match, $state, $pos) { 186 $this->_nestingTag($match, $state, $pos, 'subscript'); 187 return true; 188 } 189 190 function superscript($match, $state, $pos) { 191 $this->_nestingTag($match, $state, $pos, 'superscript'); 192 return true; 193 } 194 195 function deleted($match, $state, $pos) { 196 $this->_nestingTag($match, $state, $pos, 'deleted'); 197 return true; 198 } 199 200 201 function footnote($match, $state, $pos) { 202 // $this->_nestingTag($match, $state, $pos, 'footnote'); 203 if (!isset($this->_footnote)) $this->_footnote = false; 204 205 switch ( $state ) { 206 case DOKU_LEXER_ENTER: 207 // footnotes can not be nested - however due to limitations in lexer it can't be prevented 208 // we will still enter a new footnote mode, we just do nothing 209 if ($this->_footnote) { 210 $this->_addCall('cdata',array($match), $pos); 211 break; 212 } 213 214 $this->_footnote = true; 215 216 $ReWriter = & new Doku_Handler_Nest($this->CallWriter,'footnote_close'); 217 $this->CallWriter = & $ReWriter; 218 $this->_addCall('footnote_open', array(), $pos); 219 break; 220 case DOKU_LEXER_EXIT: 221 // check whether we have already exitted the footnote mode, can happen if the modes were nested 222 if (!$this->_footnote) { 223 $this->_addCall('cdata',array($match), $pos); 224 break; 225 } 226 227 $this->_footnote = false; 228 229 $this->_addCall('footnote_close', array(), $pos); 230 $this->CallWriter->process(); 231 $ReWriter = & $this->CallWriter; 232 $this->CallWriter = & $ReWriter->CallWriter; 233 break; 234 case DOKU_LEXER_UNMATCHED: 235 $this->_addCall('cdata', array($match), $pos); 236 break; 237 } 238 return true; 239 } 240 241 function listblock($match, $state, $pos) { 242 switch ( $state ) { 243 case DOKU_LEXER_ENTER: 244 $ReWriter = & new Doku_Handler_List($this->CallWriter); 245 $this->CallWriter = & $ReWriter; 246 $this->_addCall('list_open', array($match), $pos); 247 break; 248 case DOKU_LEXER_EXIT: 249 $this->_addCall('list_close', array(), $pos); 250 $this->CallWriter->process(); 251 $ReWriter = & $this->CallWriter; 252 $this->CallWriter = & $ReWriter->CallWriter; 253 break; 254 case DOKU_LEXER_MATCHED: 255 $this->_addCall('list_item', array($match), $pos); 256 break; 257 case DOKU_LEXER_UNMATCHED: 258 $this->_addCall('cdata', array($match), $pos); 259 break; 260 } 261 return true; 262 } 263 264 function unformatted($match, $state, $pos) { 265 if ( $state == DOKU_LEXER_UNMATCHED ) { 266 $this->_addCall('unformatted',array($match), $pos); 267 } 268 return true; 269 } 270 271 function php($match, $state, $pos) { 272 global $conf; 273 if ( $state == DOKU_LEXER_UNMATCHED ) { 274 $this->_addCall('php',array($match), $pos); 275 } 276 return true; 277 } 278 279 function phpblock($match, $state, $pos) { 280 global $conf; 281 if ( $state == DOKU_LEXER_UNMATCHED ) { 282 $this->_addCall('phpblock',array($match), $pos); 283 } 284 return true; 285 } 286 287 function html($match, $state, $pos) { 288 global $conf; 289 if ( $state == DOKU_LEXER_UNMATCHED ) { 290 $this->_addCall('html',array($match), $pos); 291 } 292 return true; 293 } 294 295 function htmlblock($match, $state, $pos) { 296 global $conf; 297 if ( $state == DOKU_LEXER_UNMATCHED ) { 298 $this->_addCall('htmlblock',array($match), $pos); 299 } 300 return true; 301 } 302 303 function preformatted($match, $state, $pos) { 304 switch ( $state ) { 305 case DOKU_LEXER_ENTER: 306 $ReWriter = & new Doku_Handler_Preformatted($this->CallWriter); 307 $this->CallWriter = & $ReWriter; 308 $this->_addCall('preformatted_start',array(), $pos); 309 break; 310 case DOKU_LEXER_EXIT: 311 $this->_addCall('preformatted_end',array(), $pos); 312 $this->CallWriter->process(); 313 $ReWriter = & $this->CallWriter; 314 $this->CallWriter = & $ReWriter->CallWriter; 315 break; 316 case DOKU_LEXER_MATCHED: 317 $this->_addCall('preformatted_newline',array(), $pos); 318 break; 319 case DOKU_LEXER_UNMATCHED: 320 $this->_addCall('preformatted_content',array($match), $pos); 321 break; 322 } 323 324 return true; 325 } 326 327 function file($match, $state, $pos) { 328 if ( $state == DOKU_LEXER_UNMATCHED ) { 329 $this->_addCall('file',array($match), $pos); 330 } 331 return true; 332 } 333 334 function quote($match, $state, $pos) { 335 336 switch ( $state ) { 337 338 case DOKU_LEXER_ENTER: 339 $ReWriter = & new Doku_Handler_Quote($this->CallWriter); 340 $this->CallWriter = & $ReWriter; 341 $this->_addCall('quote_start',array($match), $pos); 342 break; 343 344 case DOKU_LEXER_EXIT: 345 $this->_addCall('quote_end',array(), $pos); 346 $this->CallWriter->process(); 347 $ReWriter = & $this->CallWriter; 348 $this->CallWriter = & $ReWriter->CallWriter; 349 break; 350 351 case DOKU_LEXER_MATCHED: 352 $this->_addCall('quote_newline',array($match), $pos); 353 break; 354 355 case DOKU_LEXER_UNMATCHED: 356 $this->_addCall('cdata',array($match), $pos); 357 break; 358 359 } 360 361 return true; 362 } 363 364 function code($match, $state, $pos) { 365 switch ( $state ) { 366 case DOKU_LEXER_UNMATCHED: 367 $matches = preg_split('/>/u',$match,2); 368 $matches[0] = trim($matches[0]); 369 if ( trim($matches[0]) == '' ) { 370 $matches[0] = NULL; 371 } 372 # $matches[0] contains name of programming language 373 # if available, We shortcut html here. 374 if($matches[0] == 'html') $matches[0] = 'html4strict'; 375 $this->_addCall( 376 'code', 377 array($matches[1],$matches[0]), 378 $pos 379 ); 380 break; 381 } 382 return true; 383 } 384 385 function acronym($match, $state, $pos) { 386 $this->_addCall('acronym',array($match), $pos); 387 return true; 388 } 389 390 function smiley($match, $state, $pos) { 391 $this->_addCall('smiley',array($match), $pos); 392 return true; 393 } 394 395 function wordblock($match, $state, $pos) { 396 $this->_addCall('wordblock',array($match), $pos); 397 return true; 398 } 399 400 function entity($match, $state, $pos) { 401 $this->_addCall('entity',array($match), $pos); 402 return true; 403 } 404 405 function multiplyentity($match, $state, $pos) { 406 preg_match_all('/\d+/',$match,$matches); 407 $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos); 408 return true; 409 } 410 411 function singlequoteopening($match, $state, $pos) { 412 $this->_addCall('singlequoteopening',array(), $pos); 413 return true; 414 } 415 416 function singlequoteclosing($match, $state, $pos) { 417 $this->_addCall('singlequoteclosing',array(), $pos); 418 return true; 419 } 420 421 function apostrophe($match, $state, $pos) { 422