<?php
/**
* Creole parser implementation
*
* @author Josep ArĂºs
*
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_wiki
*/
include_once("wikimarkup.php");
class creole_parser extends wiki_markup_parser {
protected $blockrules = array(
'nowiki' => array(
'expression' => "/^\{\{\{(.*?)\}\}\}/ims",
'tags' => array(),
'token' => array('{{{', '}}}')
),
'header' => array(
'expression' => "/^\ *(={1,6})\ *(.+?)=*\ *$/ims",
'tags' => array(), //none
'token' => '='
),
'table' => array(
'expression' => "/^(?:\|.*?\|\ *\n)+/ims"
),
'line_break' => array(
'expression' => "/^----\s*$/im",
'token' => '----',
'tags' => array()
),
'list' => array(
'expression' => "/((?:^\ *[\*#][^\*#]\ *.+?)(?:^\ *[\*#]{1,5}\ *.+?)*)(\n\s*(?:\n|<(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)))/ims",
'tags' => array(),
'token' => array('*', '#')
),
'paragraph' => array(
'expression' => "/^\ *((?:<(?!\ *\/?(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)\ *\/?>)|[^<\s]).+?)\n\s*\n/ims",
//not specified -> all tags (null or unset)
'tag' => 'p'
)
);
protected $tagrules = array(
'nowiki' => array(
'expression' => "/\{\{\{(.*?)\}\}\}/is",
'token' => array('{{{', '}}}')
),
'image' => array(
'expression' => "/\~?\{\{(.+)\|(.+)\}\}/i",
'tags' => array(),
'token' => array('{{', '|Alt}}')
),
'link' => array(
'expression' => "/\~?\[\[(.+?)\]\]/is",
'tag' => 'a',
'token' => array('[[', ']]')
),
'url' => array(
'expression' => "/\~?(?<!=\")((?:https?|ftp):\/\/[^\s\n]+[^,\.\?!:;\"\'\n\ ])/is",
'tag' => 'a',
'token' => "http://"
),
'line_break' => array(
'expression' => "/\\\\\\\\/",
'tag' => 'br',
'simple' => true,
'token' => '----'
),
'bold' => array(
'expression' => "/\*\*(.*?)(?:\*\*|$)/is",
'tag' => 'strong',
'token' => array('**', '**')
),
'italic' => array(
'expression' => "#(?<!http:|https:|ftp:)//(.+?)(?<!http:|https:|ftp:)//#is",
'tag' => 'em',
'token' => array('//', '//')
)
);
/**
* Block hooks
*/
protected function before_parsing() {
< $this->string = htmlspecialchars($this->string);
> $this->string = htmlspecialchars($this->string, ENT_COMPAT);
parent::before_parsing();
}
public function get_section($header, $text, $clean = false) {
// The requested header is likely to have been passed to htmlspecialchars in
// self::before_parsing(), therefore we should decode it when looking for it.
< return parent::get_section(htmlspecialchars_decode($header), $text, $clean);
> return parent::get_section(htmlspecialchars_decode($header, ENT_COMPAT), $text, $clean);
}
protected function header_block_rule($match) {
$num = strlen($match[1]);
$text = trim($match[2]);
$text = preg_replace("/\s*={1,$num}$/im", "", $text);
return $this->generate_header($text, $num);
}
/**
* Table generation
*/
protected function table_block_rule($match) {
$rows = explode("\n", $match[0]);
$table = array();
foreach($rows as $r) {
if(empty($r)) {
continue;
}
$rawcells = explode("|", $r);
$cells = array();
array_shift($rawcells);
array_pop($rawcells);
foreach($rawcells as $c) {
if(!empty($c)) {
if($c[0] == "=") {
$type = 'header';
$c = substr($c, 1);
}
else {
$type = 'normal';
}
$this->rules($c);
$cells[] = array($type, $c);
}
}
$table[] = $cells;
}
return $this->generate_table($table);
}
protected function paragraph_block_rule($match) {
$text = $match[1];
foreach($this->tagrules as $tr) {
if(isset($tr['token'])) {
if(is_array($tr['token'])) {
$this->escape_token_string($text, $tr['token'][0]);
$this->escape_token_string($text, $tr['token'][1]);
}
else {
$this->escape_token_string($text, $tr['token']);
}
}
}
$this->escape_token_string($text, "~");
return $text;
}
/**
* Escape token when it is "negated"
*/
private function escape_token_string(&$text, $token) {
$text = str_replace("~".$token, $this->protect($token), $text);
}
/**
* Tag functions
*/
protected function url_tag_rule($match) {
if(strpos($match[0], "~") === 0) {
return substr($match[0], 1);
}
else {
$text = trim($match[0]);
$options = array('href' => $text);
return array($text, $options);
}
}
protected function link_tag_rule($match) {
$text = trim($match[1]);
if(strpos($match[0], "~") === 0) {
return substr($match[0], 1);
}
else {
return $this->format_link($text);
}
}
/**
* Special treatment of // ** // ** //
*/
protected function bold_tag_rule($match) {
$text = $match[1];
$this->rules($text, array('only' => array('italic')));
if(strpos($text, "//") !== false) {
$text = str_replace("//", $this->protect("//"), $text);
}
return array($text, array());
}
protected function image_tag_rule($match) {
if(strpos($match[0], "~") === 0) {
return substr($match[0], 1);
}
return $this->format_image($match[1], $match[2]);
}
}