--- a/includes/wikiformat.php Sun Mar 28 21:49:26 2010 -0400
+++ b/includes/wikiformat.php Sun Mar 28 23:10:46 2010 -0400
@@ -24,377 +24,377 @@
class Carpenter
{
- /**
- * Parser token
- * @const string
- */
-
- const PARSER_TOKEN = "\xFF";
-
- /**
- * Parsing engine
- * @var string
- */
-
- private $parser = 'mediawiki';
-
- /**
- * Rendering engine
- * @var string
- */
-
- private $renderer = 'xhtml';
-
- /**
- * Rendering flags
- */
-
- public $flags = RENDER_WIKI_DEFAULT;
-
- /**
- * List of rendering rules
- * @var array
- */
-
- private $rules = array(
- 'lang',
- 'templates',
- 'blockquote',
- 'code',
- 'tables',
- 'heading',
- 'hr',
- // note: can't be named list ("list" is a PHP language construct)
- 'multilist',
- 'bold',
- 'italic',
- 'underline',
- 'externalwithtext',
- 'externalnotext',
- 'mailtowithtext',
- 'mailtonotext',
- 'image',
- 'internallink',
- 'paragraph',
- 'blockquotepost'
- );
-
- /**
- * List of render hooks
- * @var array
- */
-
- private $hooks = array();
-
- /* private $rules = array('prefilter', 'delimiter', 'code', 'function', 'html', 'raw', 'include', 'embed', 'anchor',
- 'heading', 'toc', 'horiz', 'break', 'blockquote', 'list', 'deflist', 'table', 'image',
- 'phplookup', 'center', 'newline', 'paragraph', 'url', 'freelink', 'interwiki',
- 'wikilink', 'colortext', 'strong', 'bold', 'emphasis', 'italic', 'underline', 'tt',
- 'superscript', 'subscript', 'revise', 'tighten'); */
-
- /**
- * Render the text!
- * @param string Text to render
- * @return string
- */
-
- public function render($text)
- {
- $parser_class = "Carpenter_Parse_" . ucwords($this->parser);
- $renderer_class = "Carpenter_Render_" . ucwords($this->renderer);
-
- // empty? (don't remove this. the parser will shit bricks later about rules returning empty strings)
- if ( trim($text) === '' )
- return $text;
-
- // include files, if we haven't already
- if ( !class_exists($parser_class) )
- {
- require_once( ENANO_ROOT . "/includes/wikiengine/parse_{$this->parser}.php");
- }
-
- if ( !class_exists($renderer_class) )
- {
- require_once( ENANO_ROOT . "/includes/wikiengine/render_{$this->renderer}.php");
- }
-
- $parser = new $parser_class;
- $renderer = new $renderer_class;
-
- // run prehooks
- foreach ( $this->hooks as $hook )
- {
- if ( $hook['when'] === PO_FIRST )
- {
- $text = call_user_func($hook['callback'], $text);
- if ( !is_string($text) || empty($text) )
- {
- trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
- // *sigh*
- $text = '';
- }
- }
- }
-
- // perform render
- foreach ( $this->rules as $rule )
- {
- // run prehooks
- foreach ( $this->hooks as $hook )
- {
- if ( $hook['when'] === PO_BEFORE && $hook['rule'] === $rule )
- {
- $text = call_user_func($hook['callback'], $text);
- if ( !is_string($text) || empty($text) )
- {
- trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
- // *sigh*
- $text = '';
- }
- }
- }
-
- // execute rule
- $text_before = $text;
- $text = $this->perform_render_step($text, $rule, $parser, $renderer);
- if ( empty($text) )
- {
- trigger_error("Wikitext was completely empty after rule \"$rule\"; restoring backup", E_USER_WARNING);
- $text = $text_before;
- }
- unset($text_before);
-
- // run posthooks
- foreach ( $this->hooks as $hook )
- {
- if ( $hook['when'] === PO_AFTER && $hook['rule'] === $rule )
- {
- $text = call_user_func($hook['callback'], $text);
- if ( !is_string($text) || empty($text) )
- {
- trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
- // *sigh*
- $text = '';
- }
- }
- }
-
- RenderMan::tag_strip_push('final', $text, $final_stripdata);
- }
-
- RenderMan::tag_unstrip('final', $text, $final_stripdata);
-
- // run posthooks
- foreach ( $this->hooks as $hook )
- {
- if ( $hook['when'] === PO_LAST )
- {
- $text = call_user_func($hook['callback'], $text);
- if ( !is_string($text) || empty($text) )
- {
- trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
- // *sigh*
- $text = '';
- }
- }
- }
-
- return (( defined('ENANO_DEBUG') && isset($_GET['parserdebug']) ) ? '<pre>' . htmlspecialchars($text) . '</pre>' : $text) . "\n\n";
- }
-
- /**
- * Performs a step in the rendering process.
- * @param string Text to render
- * @param string Rule to execute
- * @param object Parser instance
- * @param object Renderer instance
- * @return string
- * @access private
- */
-
- private function perform_render_step($text, $rule, $parser, $renderer)
- {
- // First look for a direct function
- if ( function_exists("parser_{$this->parser}_{$this->renderer}_{$rule}") )
- {
- return call_user_func("parser_{$this->parser}_{$this->renderer}_{$rule}", $text, $this->flags);
- }
-
- // We don't have that, so start looking for other ways or means of doing this
- if ( method_exists($parser, $rule) && method_exists($renderer, $rule) )
- {
- // Both the parser and render have callbacks they want to use.
- $pieces = $parser->$rule($text);
- $text = call_user_func(array($renderer, $rule), $text, $pieces);
- }
- else if ( method_exists($parser, $rule) && !method_exists($renderer, $rule) && isset($renderer->rules[$rule]) )
- {
- // The parser has a callback, but the renderer does not
- $pieces = $parser->$rule($text);
- $text = $this->generic_render($text, $pieces, $renderer->rules[$rule]);
- }
- else if ( !method_exists($parser, $rule) && isset($parser->rules[$rule]) && method_exists($renderer, $rule) )
- {
- // The parser has no callback, but the renderer does
- $text = preg_replace_callback($parser->rules[$rule], array($renderer, $rule), $text);
- }
- else if ( isset($parser->rules[$rule]) && isset($renderer->rules[$rule]) )
- {
- // This is a straight-up regex only rule
- $text = preg_replace($parser->rules[$rule], $renderer->rules[$rule], $text);
- }
- else
- {
- // Either the renderer or parser does not support this rule, ignore it
- }
-
- return $text;
- }
-
- /**
- * Generic renderer
- * @access protected
- */
-
- protected function generic_render($text, $pieces, $rule)
- {
- foreach ( $pieces as $i => $piece )
- {
- $replacement = $rule;
-
- // if the piece is an array, replace $1, $2, etc. in the rule with each value in the piece
- if ( is_array($piece) )
- {
- $j = 0;
- foreach ( $piece as $part )
- {
- $j++;
- $replacement = str_replace(array("\\$j", "\${$j}"), $part, $replacement);
- }
- }
- // else, just replace \\1 or $1 in the rule with the piece
- else
- {
- $replacement = str_replace(array("\\1", "\$1"), $piece, $replacement);
- }
-
- $text = str_replace(self::generate_token($i), $replacement, $text);
- }
-
- return $text;
- }
-
- /**
- * Add a hook into the parser.
- * @param callback Function to call
- * @param int PO_* constant
- * @param string If PO_{BEFORE,AFTER} used, rule
- */
-
- public function hook($callback, $when, $rule = false)
- {
- if ( !is_int($when) )
- return null;
- if ( ($when == PO_BEFORE || $when == PO_AFTER) && !is_string($rule) )
- return null;
- if ( ( is_string($callback) && !function_exists($callback) ) || ( is_array($callback) && !method_exists($callback[0], $callback[1]) ) || ( !is_string($callback) && !is_array($callback) ) )
- {
- trigger_error("Attempt to hook with undefined function/method " . print_r($callback, true), E_USER_ERROR);
- return null;
- }
-
- $this->hooks[] = array(
- 'callback' => $callback,
- 'when' => $when,
- 'rule' => $rule
- );
- }
-
- /**
- * Disable a render stage
- * @param string stage
- * @return null
- */
-
- public function disable_rule($rule)
- {
- foreach ( $this->rules as $i => $current_rule )
- {
- if ( $current_rule === $rule )
- {
- unset($this->rules[$i]);
- return null;
- }
- }
- return null;
- }
-
- /**
- * Disables all rules.
- * @return null
- */
-
- public function disable_all_rules()
- {
- $this->rules = array();
- return null;
- }
-
- /**
- * Enables a rule
- * @param string rule
- * @return null
- */
-
- public function enable_rule($rule)
- {
- $this->rules[] = $rule;
- return null;
- }
-
- /**
- * Make a rule exclusive (the only one called)
- * @param string stage
- * @return null
- */
-
- public function exclusive_rule($rule)
- {
- if ( is_string($rule) )
- $this->rules = array($rule);
-
- return null;
- }
-
- /**
- * Generate a token
- * @param int Token index
- * @return string
- * @static
- */
-
- public static function generate_token($i)
- {
- return self::PARSER_TOKEN . $i . self::PARSER_TOKEN;
- }
-
- /**
- * Tokenize string
- * @param string
- * @param array Matches
- * @return string
- * @static
- */
-
- public static function tokenize($text, $matches)
- {
- $matches = array_values($matches);
- foreach ( $matches as $i => $match )
- {
- $text = str_replace_once($match, self::generate_token($i), $text);
- }
-
- return $text;
- }
+ /**
+ * Parser token
+ * @const string
+ */
+
+ const PARSER_TOKEN = "\xFF";
+
+ /**
+ * Parsing engine
+ * @var string
+ */
+
+ private $parser = 'mediawiki';
+
+ /**
+ * Rendering engine
+ * @var string
+ */
+
+ private $renderer = 'xhtml';
+
+ /**
+ * Rendering flags
+ */
+
+ public $flags = RENDER_WIKI_DEFAULT;
+
+ /**
+ * List of rendering rules
+ * @var array
+ */
+
+ private $rules = array(
+ 'lang',
+ 'templates',
+ 'blockquote',
+ 'code',
+ 'tables',
+ 'heading',
+ 'hr',
+ // note: can't be named list ("list" is a PHP language construct)
+ 'multilist',
+ 'bold',
+ 'italic',
+ 'underline',
+ 'externalwithtext',
+ 'externalnotext',
+ 'mailtowithtext',
+ 'mailtonotext',
+ 'image',
+ 'internallink',
+ 'paragraph',
+ 'blockquotepost'
+ );
+
+ /**
+ * List of render hooks
+ * @var array
+ */
+
+ private $hooks = array();
+
+ /* private $rules = array('prefilter', 'delimiter', 'code', 'function', 'html', 'raw', 'include', 'embed', 'anchor',
+ 'heading', 'toc', 'horiz', 'break', 'blockquote', 'list', 'deflist', 'table', 'image',
+ 'phplookup', 'center', 'newline', 'paragraph', 'url', 'freelink', 'interwiki',
+ 'wikilink', 'colortext', 'strong', 'bold', 'emphasis', 'italic', 'underline', 'tt',
+ 'superscript', 'subscript', 'revise', 'tighten'); */
+
+ /**
+ * Render the text!
+ * @param string Text to render
+ * @return string
+ */
+
+ public function render($text)
+ {
+ $parser_class = "Carpenter_Parse_" . ucwords($this->parser);
+ $renderer_class = "Carpenter_Render_" . ucwords($this->renderer);
+
+ // empty? (don't remove this. the parser will shit bricks later about rules returning empty strings)
+ if ( trim($text) === '' )
+ return $text;
+
+ // include files, if we haven't already
+ if ( !class_exists($parser_class) )
+ {
+ require_once( ENANO_ROOT . "/includes/wikiengine/parse_{$this->parser}.php");
+ }
+
+ if ( !class_exists($renderer_class) )
+ {
+ require_once( ENANO_ROOT . "/includes/wikiengine/render_{$this->renderer}.php");
+ }
+
+ $parser = new $parser_class;
+ $renderer = new $renderer_class;
+
+ // run prehooks
+ foreach ( $this->hooks as $hook )
+ {
+ if ( $hook['when'] === PO_FIRST )
+ {
+ $text = call_user_func($hook['callback'], $text);
+ if ( !is_string($text) || empty($text) )
+ {
+ trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
+ // *sigh*
+ $text = '';
+ }
+ }
+ }
+
+ // perform render
+ foreach ( $this->rules as $rule )
+ {
+ // run prehooks
+ foreach ( $this->hooks as $hook )
+ {
+ if ( $hook['when'] === PO_BEFORE && $hook['rule'] === $rule )
+ {
+ $text = call_user_func($hook['callback'], $text);
+ if ( !is_string($text) || empty($text) )
+ {
+ trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
+ // *sigh*
+ $text = '';
+ }
+ }
+ }
+
+ // execute rule
+ $text_before = $text;
+ $text = $this->perform_render_step($text, $rule, $parser, $renderer);
+ if ( empty($text) )
+ {
+ trigger_error("Wikitext was completely empty after rule \"$rule\"; restoring backup", E_USER_WARNING);
+ $text = $text_before;
+ }
+ unset($text_before);
+
+ // run posthooks
+ foreach ( $this->hooks as $hook )
+ {
+ if ( $hook['when'] === PO_AFTER && $hook['rule'] === $rule )
+ {
+ $text = call_user_func($hook['callback'], $text);
+ if ( !is_string($text) || empty($text) )
+ {
+ trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
+ // *sigh*
+ $text = '';
+ }
+ }
+ }
+
+ RenderMan::tag_strip_push('final', $text, $final_stripdata);
+ }
+
+ RenderMan::tag_unstrip('final', $text, $final_stripdata);
+
+ // run posthooks
+ foreach ( $this->hooks as $hook )
+ {
+ if ( $hook['when'] === PO_LAST )
+ {
+ $text = call_user_func($hook['callback'], $text);
+ if ( !is_string($text) || empty($text) )
+ {
+ trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING);
+ // *sigh*
+ $text = '';
+ }
+ }
+ }
+
+ return (( defined('ENANO_DEBUG') && isset($_GET['parserdebug']) ) ? '<pre>' . htmlspecialchars($text) . '</pre>' : $text) . "\n\n";
+ }
+
+ /**
+ * Performs a step in the rendering process.
+ * @param string Text to render
+ * @param string Rule to execute
+ * @param object Parser instance
+ * @param object Renderer instance
+ * @return string
+ * @access private
+ */
+
+ private function perform_render_step($text, $rule, $parser, $renderer)
+ {
+ // First look for a direct function
+ if ( function_exists("parser_{$this->parser}_{$this->renderer}_{$rule}") )
+ {
+ return call_user_func("parser_{$this->parser}_{$this->renderer}_{$rule}", $text, $this->flags);
+ }
+
+ // We don't have that, so start looking for other ways or means of doing this
+ if ( method_exists($parser, $rule) && method_exists($renderer, $rule) )
+ {
+ // Both the parser and render have callbacks they want to use.
+ $pieces = $parser->$rule($text);
+ $text = call_user_func(array($renderer, $rule), $text, $pieces);
+ }
+ else if ( method_exists($parser, $rule) && !method_exists($renderer, $rule) && isset($renderer->rules[$rule]) )
+ {
+ // The parser has a callback, but the renderer does not
+ $pieces = $parser->$rule($text);
+ $text = $this->generic_render($text, $pieces, $renderer->rules[$rule]);
+ }
+ else if ( !method_exists($parser, $rule) && isset($parser->rules[$rule]) && method_exists($renderer, $rule) )
+ {
+ // The parser has no callback, but the renderer does
+ $text = preg_replace_callback($parser->rules[$rule], array($renderer, $rule), $text);
+ }
+ else if ( isset($parser->rules[$rule]) && isset($renderer->rules[$rule]) )
+ {
+ // This is a straight-up regex only rule
+ $text = preg_replace($parser->rules[$rule], $renderer->rules[$rule], $text);
+ }
+ else
+ {
+ // Either the renderer or parser does not support this rule, ignore it
+ }
+
+ return $text;
+ }
+
+ /**
+ * Generic renderer
+ * @access protected
+ */
+
+ protected function generic_render($text, $pieces, $rule)
+ {
+ foreach ( $pieces as $i => $piece )
+ {
+ $replacement = $rule;
+
+ // if the piece is an array, replace $1, $2, etc. in the rule with each value in the piece
+ if ( is_array($piece) )
+ {
+ $j = 0;
+ foreach ( $piece as $part )
+ {
+ $j++;
+ $replacement = str_replace(array("\\$j", "\${$j}"), $part, $replacement);
+ }
+ }
+ // else, just replace \\1 or $1 in the rule with the piece
+ else
+ {
+ $replacement = str_replace(array("\\1", "\$1"), $piece, $replacement);
+ }
+
+ $text = str_replace(self::generate_token($i), $replacement, $text);
+ }
+
+ return $text;
+ }
+
+ /**
+ * Add a hook into the parser.
+ * @param callback Function to call
+ * @param int PO_* constant
+ * @param string If PO_{BEFORE,AFTER} used, rule
+ */
+
+ public function hook($callback, $when, $rule = false)
+ {
+ if ( !is_int($when) )
+ return null;
+ if ( ($when == PO_BEFORE || $when == PO_AFTER) && !is_string($rule) )
+ return null;
+ if ( ( is_string($callback) && !function_exists($callback) ) || ( is_array($callback) && !method_exists($callback[0], $callback[1]) ) || ( !is_string($callback) && !is_array($callback) ) )
+ {
+ trigger_error("Attempt to hook with undefined function/method " . print_r($callback, true), E_USER_ERROR);
+ return null;
+ }
+
+ $this->hooks[] = array(
+ 'callback' => $callback,
+ 'when' => $when,
+ 'rule' => $rule
+ );
+ }
+
+ /**
+ * Disable a render stage
+ * @param string stage
+ * @return null
+ */
+
+ public function disable_rule($rule)
+ {
+ foreach ( $this->rules as $i => $current_rule )
+ {
+ if ( $current_rule === $rule )
+ {
+ unset($this->rules[$i]);
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Disables all rules.
+ * @return null
+ */
+
+ public function disable_all_rules()
+ {
+ $this->rules = array();
+ return null;
+ }
+
+ /**
+ * Enables a rule
+ * @param string rule
+ * @return null
+ */
+
+ public function enable_rule($rule)
+ {
+ $this->rules[] = $rule;
+ return null;
+ }
+
+ /**
+ * Make a rule exclusive (the only one called)
+ * @param string stage
+ * @return null
+ */
+
+ public function exclusive_rule($rule)
+ {
+ if ( is_string($rule) )
+ $this->rules = array($rule);
+
+ return null;
+ }
+
+ /**
+ * Generate a token
+ * @param int Token index
+ * @return string
+ * @static
+ */
+
+ public static function generate_token($i)
+ {
+ return self::PARSER_TOKEN . $i . self::PARSER_TOKEN;
+ }
+
+ /**
+ * Tokenize string
+ * @param string
+ * @param array Matches
+ * @return string
+ * @static
+ */
+
+ public static function tokenize($text, $matches)
+ {
+ $matches = array_values($matches);
+ foreach ( $matches as $i => $match )
+ {
+ $text = str_replace_once($match, self::generate_token($i), $text);
+ }
+
+ return $text;
+ }
}