Location: PHPKode > scripts > YBBtags > ybbtags/class_YBBtags.php
<?php
/**
*
* YapBB's Bulletin Board Tags class v2.18
*
* YapBB's Tags class has functionality typically found in discussion board
* systems ('forums'). YBBtags originates from the YapBB forum system. Class
* objects can easily process text by specifying the actions to perform on the
* represented text. These include PHP code highlighting (both PHP3 and PHP4),
* lists, simple formatting, IRC-style schizophrenia, division of the
* represented text into quote/code blocks, handling of smilies, and more.
* Actions can be specified at run time, e.g. depending on variables defined
* in the calling script.
*
* http://yapbb.sourceforge.net/YBBtags/
*
*
* <code>--------------
*  Example Usage:
* --------------</code>
*
* #  We assume that $text already contains a text, $smiles is
* #  an array in the proper format (see constructor), $sessionUser
* #  contains a description of the person who made the
* #  HTTP request and that this file has already been included
* #  into the project somewhere.
*
*  <code>
*  $YBB = new YBBtags($text, $smiles, "./images/", $sessionUser);
*
*  $operations = "";
*  if ($useHTML == 0) $operations .= $YBB->OP_NOHTML;
*  if ($highlightcode == 1) $operations .= $YBB->OP_PHP;
*  $operations .= $YBB->OP_SIMPLE;
*  $operations .= $YBB->OP_SMILIES;
*  $operations .= $YBB->OP_QUOTE;
*
*  $text = $YBB->pgetText($operations);
*  </code>
*
* #  Done! $text now contains the parsed version of the
* #  original $text.
*
*
* <code>------
*  Notes:
* ------</code>
*
* o In order to alter the resulting HTML produced by <code>[code], [php],
*   [quote] and [img2]</code> tags, please alter the <code>encapsulate()</code> method
*   of this class.
*   By default it assumes presence of a style sheet with elements
*   named <code>'code', 'quote' and 'image'</code> (which can be applied to <code><tr></code>
*   elements), which would be used for decoration.
*
* o The <code>[me=XYZ]</code> and <code>[you]</code> tags assume that style sheet elements
*   with the names 'me' and 'you' respectively, are availlable
*   and can be applied to <code><span></code> elements. Look for
*   <code>"case $this->OP_PERSONAL:"</code> in this class and change the
*   appropriate code.
*
* o YBBtags has been succesfully tested on PHP4.0.6 and PHP3.0.17
*   on Windows platform and on PHP4.0.3pl1 on Linux platform.
*
* o The NL2BR and NBSP operarators are always handled last (if present) and
*   the NOHTML or SAFEHTML operators are always handled first (if present).
*
* o In order to add the original '/me' capability, use the following regular expression
*   before passing text to instances of this class:
*   <code>
*   // Me function by hide@address.com :
*   $expression = "!(^|[ \t])/me (.*)$!im";
*   $replacement = "\\1[me=" . $userNickName . "]\\2[/me]";
*   $text = preg_replace($expression, $replacement, $text);
*   </code>
*   In the context of a forum system, <code>$userNickName</code> should contain the username of
*   the person who posted the message that is being processed.
*
* o Processing of string highlighting in PHP3 is VERY CPU intensive and should probably not
*   not be enabled when used with large text fragments.
*
*
* <code>------------
*  Limitations:
* ------------</code>
*
* o The appearance of a code, php or quote segment inside a list
*   segment does not give the desired effect, because of the way
*   these segments are split up.
*
* o The same limitation does *NOT* go for a code or php segment
*   inside a quote segment.
*
* o In general, segments inside another segment of the same kind
*   do not function.
*
*
* <code>--------
* Changes:
* --------</code>
*
* o New in 2.18:
*   x Changed the constructor to now check if PHP is running in
*     safe mode or not, before attempting to reset the time out
*   x Changed the resulting HTML of the <code>[edit]</code> tag
*
* o New in 2.17:
*   x Bug fix in <code>processTypes()</code>. Now <code>$operations</code> is first inspected for types,
*     *then* individual actions are taken in a predefined sequence. Altering this sequence
*     could cause problems
*   x Bug fix: now &amp;&amp;nbsp;'s are added based on the <code>$OP_NBSP</code> operator,
*     not the <code>$OP_NL2BR</code> operator
*   x Bug fix in the simple markup tags for PHP3
*
* o New in 2.16:
*   x Bug fix in the <code>[edit]</code> tag (language array was not properly used)
*   x Bug fix in the <code>[list]</code> tag ('variables' were not handled properly, ie such sequences: $aVar)
*
* o New in 2.15:
*   x Documentation changes
*   x Bug fix for the <code>[rev]</code> tag-processor - the PHP3 and PHP4 blocks were mistakenly swapped
*   x Split <code>$OP_CODE</code> into <code>$OP_CODE</code> (for normal <code>[code]</code>) and <code>$OP_PHP</code> (for <code>[php]</code> code)
*     (now the example finally is 100% accurate as well ;))
*
* o New in 2.14:
*   x Documentation changes
*   x Added new <code>[rev]</code> markup tag to reverse the contents of its body
*   x Previously, the <code>$OP_NL2BR</code> operator was handled at the point it was encountered,
*     but now it's always handled last in line. Same goes for <code>$OP_NOHTML</code> and
*     <code>$OP_SAFEHTML</code> (which are both handled first). Now the order in which the operators
*     appear, that are passed to <code>parse()</code>, does not matter anymore.
*   x Now all operators are 2-char strings, to allow for easier future expansion
*     (of course this does not interfere with normal operation in any way)
*   x Added the OP_NBSP operator.
*   x Changed code for locating operators in <code>$operations</code>, since operators are now 2-char strings
*
* o New in 2.13:
*   x Insignificant documentation changes
*   x Bug fix when using upper case tags for code, php or quote
*   x Added simple markup tags: <code>[sub]</code> and <code>[sup]</code>
*
* o New in 2.12:
*   x Small typo in documentation corrected
*   x Added more documentation on how to use the supported tags
*   x Fixed some more documentation
*   x Added more links and cross references
*   x When code is encapsulated, it's nolonger wrapped (see <code>_encapsulate()</code>)
*     (The prefered way is to add the nowrap style to the code element in
*      the CSS.)
*   x Bug fix when "reversing" <code>&amp;amp;amp;#code;</code> back to <code>&amp;#code;</code> (with HTML disabled)
*
* o New in 2.11:
*   x Bug fix: [me=XYZ] now works correctly
*   x Small documentation changes
*   x Removed redundant <code>_generate_ereg()</code>
*   x Other small code changes
*
* o New in 2.10:
*   x Re-instated array_values and array_keys emulation
*   x [list] now finally works on PHP3
*   x Optimized the code a bit
*   x PHP highlighting now fully functional for PHP3 (though
*     VERY slow)
*   x YBBtags now tries to disable the script-timeout setting
*   x Made the $smilies array a required parameter to the
*     constructor. (For the sake of the PHPDoc system.)
*     Previously $smilies was an optional argument
*
* o New in 2.9:
*   x Added highlight functionality for PHP3 (buggy, so disabled)
*   x Removed array_values and array_keys emulation
*
* o New in 2.8:
*   x Started keeping changelog
*   x Added the OP_APPEARANCE operator (derived from OP_SIMPLE)
*   x Some code cleanup
*   x Cleaned up the documentation as well as adding new ones
*
*
* <code>-----------------
*  Integral part of:
* -----------------</code>
*
* YapBB, a fully functional bulletin board system
* Copyright (C) 2001  Arno van der Kolk, Sven Vintges
* http://yapbb.sourceforge.net/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* @author		Arno van der Kolk <hide@address.com>
* @copyright	&copy; 2001  Arno van der Kolk
* @link			http://yapbb.sourceforge.net/YBBtags/									YBBtags Home Page
* @link			http://yapbb.sourceforge.net/											YapBB Website
* @link			http://freshmeat.net/projects/YBBtags/									YBBtags on freshmeat.net
* @link			http://yapbb.sourceforge.net/article.php?sid=3&mode=threaded?menu=13	GNU Public License
* @link			http://yapbb.sourceforge.net/forum/faq.php#ybb							Full list of supported tags
* @version		2.18
* @access		public
*
*/
class YBBtags
{
	/**
	* Information for serialization
	*
	* @access	public
	* @static
	* @final
	* @var		string	$classname
	* @link		http://www.yapbb.net/serialize
	* @since	2.0
	*/
	var $classname = "YBBtags";

	/**
	* For keeping track if this instance has already been parsed (instances won't parse more than once)
	*
	* @access	private
	* @var		boolean	$_hasparsed
	* @since	2.0
	*/
	var $_hasparsed = false;

	/**
	* For keeping track of all the text segments
	*
	* This array is automatically filled in <code>_split</code>.
	*
	* @access	private
	* @var		array	$_segments
	* @see		_split()
	* @since	2.0
	*/
	var $_segments = array();

	/**
	* For keeping track of the types of all the text segments
	*
	* This array is automatically filled in <code>_split</code>.
	*
	* @access	private
	* @var		array	$_types
	* @see		_split()
	* @since	2.0
	*/
	var $_types = array();

	/**
	* Are we dealing with some anitique PHP3 system? ;)
	*
	* This is automatically set in constructor.
	* (In previous 2.x versions this was called <code>_isPHP4</code>.)
	*
	* @access	private
	* @static
	* @var		boolean	$_isPHP3
	* @see		YBBtags()
	* @since	2.8
	*/
	var $_isPHP3;

	/**
	* Pointer to the array that contains the smilies
	*
	* This is set through a constructor parameter.
	*
	* @access	private
	* @var		array	$_smilies
	* @see		YBBtags()
	* @since	2.0
	*/
	var $_smilies;

	/**
	* Should contain the URI where the supporting images can be located
	*
	* This is set through a constructor parameter.
	*
	* @access	private
	* @var		string	$_imgURL
	* @see		YBBtags()
	* @since	2.0
	*/
	var $_imgURL;

	/**
	* Should contain a string identifying the reader of the represented text
	*
	* This is set through a constructor parameter.
	*
	* @access	private
	* @var		string	$_reader
	* @see		YBBtags()
	* @since	2.0
	*/
	var $_reader;

	/**
	* Used to mark segment as normal (plain text)
	*
	* @access	private
	* @static
	* @final
	* @var		integer	$_TYPE_NORMAL
	* @since	2.0
	*/
	var $_TYPE_NORMAL = 1;

	/**
	* Used to mark segment as code
	*
	* @access	private
	* @static
	* @final
	* @var		integer	$_TYPE_CODE
	* @since	2.0
	*/
	var $_TYPE_CODE = 2;

	/**
	* Used to mark segment as PHP code
	*
	* @access	private
	* @static
	* @final
	* @var		integer	$_TYPE_PHP
	* @since	2.0
	*/
	var $_TYPE_PHP = 3;

	/**
	* Used to mark segment as quote
	*
	* @access	private
	* @static
	* @final
	* @var		integer	$_TYPE_QUOTE
	* @since	2.3
	*/
	var $_TYPE_QUOTE = 4;

	/**
	* Operator: Disable all HTML by converting <, > and & to &amp;amp;lt;, &amp;amp;gt; and &amp;amp;amp; respectively
	*
	* Note that all occurances of <code>&amp;amp;#code;</code> and <code>&amp;amp;XYZ;</code> are converted back for added flexibility.
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_NOHTML
	* @since	2.0
	*/
	var $OP_NOHTML = "NH";

	/**
	* Operator: Only disable dangerous HTML (has no effect when <code>$OP_NOHTML</code> is also set)
	*
	* This includes <code><td>, <tr>, <table>, <th>, <script>, <meta>, <xmp>, <html>, <body>, <head>, <textarea></code>.
	* Also, the <code>style</code> attribute for all elements has been disabled.
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_SAFEHTML
	* @see		$OP_NOHTML
	* @since	2.0
	*/
	var $OP_SAFEHTML = "SH";

	/**
	* Operator: Process smilies (replace smile-codes with their pictures)
	*
	* See constructor for format of the smilies array.
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_SMILIES
	* @see		YBBtags()
	* @since	2.0
	*/
	var $OP_SMILIES = "EM";

	/**
	* Operator: Process [list] tags
	*
	* The proper format is:
	* <code>
	* [list]
	* [*]Text 1
	* [*]Text 2
	* [*]Text 3
	* [/list]
	* </code>
	* Result is:
	* <code>
	* <ul>
	* <li>Text 1</li>
	* <li>Text 2</li>
	* <li>Text 3</li>
	* </ul>
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_LIST
	* @see		_create_listitems()
	* @since	2.0
	*/
	var $OP_LIST = "LI";

	/**
	* Operator: Process simple markup tags
	*
	* This includes:
	* <code>
	* [b]bold[/b] --> <b>bold</b>
	* [i]italic[/i] --> <i>italic</i>
	* [u]underline[/u] --> <u>underline</u>
	* [s]strike-through[/s] --> <s>strike-through</s>
	* [tt]teletype font[/tt] --> <tt>teletype font</tt>
	* [sub]subscript[/sub] --> <sub>subscript</sub>
	* [sup]superscript[/sup] --> <sup>superscript</sup>
	* [hr] --> <hr>
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_SIMPLE
	* @since	2.0
	*/
	var $OP_SIMPLE = "SM";

	/**
	* Operator: Process color and size of text
	*
	* This includes:
	* <code>
	* [color=XYZ]text[/color] --> <font color="XYZ">text</font>
	* [size=XYZ]text[/size] --> <font size="XYZ">text</font>
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_APPEARANCE
	* @since	2.8
	*/
	var $OP_APPEARANCE = "AP";

	/**
	* Operator: Treat code segments as code (in stead of plain text segments)
	*
	* This includes:
	*
	* <code>[code]text[/code]</code>
	*
	* (see <code>_encapsulate()</code> for resulting HTML)
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_CODE
	* @see		_encapsulate()
	* @since	2.0
	*/
	var $OP_CODE = "CO";

	/**
	* Operator: Treat PHP code segments as code (in stead of plain text segments)
	*
	* This includes:
	*
	* <code>[php]text[/php]</code>
	*
	* (see <code>_encapsulate()</code> for resulting HTML)
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_PHP
	* @see		_encapsulate()
	* @since	2.15
	*/
	var $OP_PHP = "PC";

	/**
	* Operator: Process [quote]
	*
	* This includes:
	*
	* <code>[quote]text[/quote]</code>
	*
	* (see <code>_encapsulate()</code> for resulting HTML)
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_QUOTE
	* @see		_encapsulate()
	* @since	2.0
	*/
	var $OP_QUOTE = "QU";

	/**
	* Operator: Process [email], [url] and make links clickable
	*
	* This includes:
	* <code>
	* [email]XYZ[/email] --> <a href="mailto:XYZ">XYZ</a>
	*
	* [email=ABC]XYZ[/email] --> <a href="mailto:ABC">XYZ</a>
	*
	* hide@address.com -->
	* <a href="mailto:hide@address.com">hide@address.com</a> (automatic conversion)
	*
	* [url]XYZ[/url] --> <a href="XYZ">XYZ</a>
	*
	* [url=ABC]XYZ[/url] --> <a href="ABC">XYZ</a>
	*
	* http://url.domain.com/page -->
	* <a href="http://url.domain.com/page">http://url.domain.com/page</a> (automatic conversion)
	* </code>
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_URLS
	* @since	2.0
	*/
	var $OP_URLS = "HL";

	/**
	* Operator: Perform miscelaneous operations
	*
	* This includes:
	* <code>
	* [offtopic]text[/offtopic] --> <small>Offtopic:<br>text</small></code> (used for small unimportant notes)<code>
	* [off topic]text[/off topic] --> <small>Off topic:<br>text</small></code> (used for small unimportant notes)<code>
	* [edit]text[/edit] --> Edit:<br><i>text</i></code> (used to mark a note that was added later)<code>
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_MISC
	* @since	2.0
	*/
	var $OP_MISC = "MC";

	/**
	* Operator: Replace newlines with html-breaks
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_NL2BR
	* @link		http://www.php.net/nl2br
	* @since	2.0
	*/
	var $OP_NL2BR = "NB";

	/**
	* Operator: Replace spaces and tabs with &amp;amp;nbsp;
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_NBSP
	* @since	2.14
	*/
	var $OP_NBSP = "SC";

	/**
	* Operator: Process [me=XYZ] and [you] tags
	*
	* This includes:
	*
	* <code>[you] --> <span class="you">(you)</span></code> ((you) represents the string specified to the constructor)
	* <code>[me=XYZ]text[/me] --> <span style='display: block' class='me'>» XYZ text</span></code>
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_PERSONAL
	* @see		YBBtags()
	* @since	2.0
	*/
	var $OP_PERSONAL = "PI";

	/**
	* Operator: Process [img] and [img2] tags
	*
	* This includes:
	* <code>
	* [img]XYZ[/img] --> <img src="XYZ" alt="picture: XYZ">
	* [img2]XYZ[/img2] --> <a href="XYZ" target="_blank"><img src="icon.gif" alt="picture: XYZ"></a></code> (see also code in <code>_encapsulate()</code>)<code>
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_IMAGES
	* @see		_encapsulate()
	* @since	2.0
	*/
	var $OP_IMAGES = "IM";

	/**
	* Operator: Process [rev]
	*
	* This includes:
	* <code>
	* [rev]a sample text[/rev] --> txet elpmas a
	* </code>
	* @access	public
	* @static
	* @final
	* @var		string	$OP_REVERSE
	* @since	2.14
	*/
	var $OP_REVERSE = "BW";

	/**
	* Operator: Perform all available operations in a pre-defined sequence
	*
	* This operator is ignored when used in conjunction with other operations.
	* See the code of <code>_processNormal()</code> for exact sequence.
	*
	* @access	public
	* @static
	* @final
	* @var		string	$OP_ALL
	* @see		_processNormal()
	* @since	2.0
	*/
	var $OP_ALL = "AL";

	/**
	* This array contains language specific information.
	*
	* You should modify the contents of this array, which is hard coded in the constructor,
	* when you want to translate certain output generated by class objects.
	*
	* @access	private
	* @static
	* @var		array	$lang
	* @see		YBBtags()
	* @since	2.0
	*/
	var $lang = array();



	/**
	* Constructor, used to construct new class objects ('instances').
	*
	* The passed text is automatically split into segments by <code>_split()</code>.
	*
	* @access	public
	* @param	string	$text			Text to represent
	* @param	array	$smilies		An array of smiles.
	*
	* The proper format of this array is:
	* <code>array(array("" => "blank.gif"), array(":)" => "smile.gif"), array(":(" => "sad.gif"))</code>
	*
	* Note that only items with non-empty keys ("") are processed.
	* @param	string	$picURL			Directory (or URI) where to locate the required images (icon.gif and pixel.gif).
	*
	* icon.gif is used to represent images that are inserted into the text using the [img2] tag
	* pixel.gif is used to provide better layout support for browsers
	* @param	string	$reader			The name or description of the reader/viewer of the represented text (if appropriate)
	* (used by [you] - $OP_PERSONAL)
	* @return	object	YBBtags			A new instance of this class
	* @see		$OP_PERSONAL, _split()
	* @since	1.0
	*/
	function YBBtags($text, $smilies, $picURL = "", $reader = "you")
	{
		if (function_exists("set_time_limit") && !get_cfg_var('safe_mode'))	// Static initializer (to disable time limit)
			set_time_limit(0);

																			// Conduct preliminary tests
		if (!is_array($smilies) || count($this->arraykeys($smilies)) == 0 || count($this->arrayvalues($smilies)) == 0)
		{
			$smilies = array();
			echo '<pre>Warning: Wrong format for $smilies array!</pre>';
		}

		if (substr($picURL, -1, 1) != "/")
			$picURL = "$picURL/";

		$this->lang['quote'] = "quote";										// If you plan on translating this array,
		$this->lang['code'] = "code";										// DO NOT ALTER THE KEYS!
		$this->lang['image'] = "picture";									// Only modify the values!
		$this->lang['edit'] = "Edit";
		$this->lang['guest'] = "Visitor";

																			// Assign attributes
		$this->_smilies = $smilies;
		$this->_imgURL = $picURL;
		$this->_reader = $reader;
		$this->_isPHP3 = floor(phpversion()) < 4;
		$this->_split($text);												// Automatically begin dividing the text into sections
	} // end constructor


	/**
	* Splits the text into segments (recursively), called by the constructor
	*
	* You should not call this function directly. Since it's not a static, it *COULD*
	* mess things up.
	*
	* @access	private
	* @param	string	$text	Text to further split up
	* @see		YBBtags()
	* @since	2.0
	*/
	function _split($text)
	{
		$expression = "!(.*)\[(quote|code|php)\](.+)\[/\\2\](.*?)!Uis";		// technical note: quote should appear before code and php (so that it may contain one of the others)
		if (preg_match($expression, $text, $matches))
		{
			if ($matches[1] != "")											// if we have something...
			{
				$this->_segments[] = $matches[1];							// ... stockpile it
				$this->_types[] = $this->_TYPE_NORMAL;						// ... and mark it as a normal segment
			}

			$this->_segments[] = $matches[3];								// stockpile the found segment...
			switch (strtolower($matches[2]))								// ... and mark it correctly
			{
				case "php":
					$this->_types[] = $this->_TYPE_PHP;
					break;
				case "code":
					$this->_types[] = $this->_TYPE_CODE;
					break;
				case "quote":
					$this->_types[] = $this->_TYPE_QUOTE;
					break;
				default:													// error (should not even be happening!)
					die("Parse error: unknown type (" . $matches[2] . ")");
					break;
			}

			$this->_split($matches[4]);										// split the rest (recursive call)
		}
		else																// no new segment found (ie: the rest has no code or PHP or quote)
		{
			$this->_segments[] = $text;										// add that text
			$this->_types[] = $this->_TYPE_NORMAL;							// and mark it as normal
		}
	} // end func _split


	/**
	* Process all found segments and parse each one.
	*
	* This function actually sets the parse process into motion. Afterwards the
	* <code>getText</code> method can be called to retrieve the parsed text.
	*
	* @access	public
	* @param	string	$operations	Operations to perform on the represented text
	* @see		_processTypes()
	* @since	1.0
	*/
	function parse($operations)
	{
		$operations = strtoupper($operations);

		$count = count($this->_segments);
		for ($i = 0; !$this->_hasparsed && $i < $count; $i++)				// step through each segment
			$this->_segments[$i] = $this->_processTypes($this->_segments[$i], $operations, $this->_types[$i]);
		unset($count);
		unset($i);

		$this->_hasparsed = true;
	} // end func parse


	/**
	* Auxillary parse function, called from <code>parse()</code>, calls <code>_processNormal()</code>
	*
	* You should not call this function directly. But since it's a static, it could not
	* possibly do any harm. :)
	*
	* @access	private
	* @static
	* @param	string	$text				The text to process
	* @param	string	$operations			The operations to perform
	* @param	integer	$type				Type of the text
	* @return	string						The processed text
	* @see		_processNormal(), parse()
	* @since	2.3
	*/
	function _processTypes($text, $operations, $type)
	{
		switch ($type)														// determine current segment's type
		{
			case $this->_TYPE_QUOTE:										// is a quote (treat it as an entirely new piece of text)
			{
				$recursiveYBB = new YBBtags($text, $this->_smilies, $this->_imgURL, $this->_reader);
				$text = $recursiveYBB->pgetText($operations);				// recursively parse it
				unset($recursiveYBB);

				if ($this->_has_operator($operations, $this->OP_NL2BR))		// encapsulate the result into a quote (if enabled)
					$text = $this->_encapsulate('quote', $text);
				break;
			}
			case $this->_TYPE_PHP:											// is PHP code segment
			{
				if ($this->_has_operator($operations, $this->OP_PHP))		// is PHP code parsing enabled?
				{
					if (!$this->_isPHP3)									// PHP3 has no highlight built in
					{
						$text = ("<" . "?\n$text\n?" . ">");
						ob_start();
						highlight_string($text);
						$text = ob_get_contents();
						ob_end_clean();
						$text = $this->_encapsulate('code', $text);
					}
					else
						$text = $this->_encapsulate('code', trim($this->highlightstring("<" . "?$text?" . ">")));

					break;
				}
				else
					;	// see? no break; so continue to next
			}
			case $this->_TYPE_CODE:											// is regular code segment
			{
				if ($this->_has_operator($operations, $this->OP_CODE))		// is code parsing enabled?
				{
					$text = $this->_encapsulate('code', nl2br(str_replace(' ', '&nbsp;', str_replace("\t", '&nbsp;&nbsp;&nbsp;&nbsp;', htmlentities("$text\n")))));
					break;
				}
																			// else, treat as normal segment

				// see? no break; so continue to next
			}
			case $this->_TYPE_NORMAL:										// is normal (non-code) segment
			{
				$text = $this->_processNormal($text, $operations);
				break;
			}
			default:														// ERROR! (should not even be happening)
			{
				die("parse error ($i: ." . $text . ". - $operations)!");
				break;
			}
		}

		return $text;
	} // end func _processTypes


	/**
	* Process the 'normal' segments (that are neither code, PHP or quote).
	*
	* You should not call this function directly. But since it's a static, it could not
	* possibly do any harm. :)
	*
	* @access	private
	* @static
	* @param	string	$text		The text to process
	* @param	string	$operations	The operations to perform
	* @return	string				The processed text
	* @see		_processTypes()
	* @todo							Fix the nested simple markup bug for PHP3
	*								Fix the ' and \ in img2 urls (not really necessary though)
	* @since	2.3
	*/
	function _processNormal($text, $operations)
	{
		$op = array();
		$len = strlen($operations);
		for ($j = 0; $j < $len; $j += 2)
		{
			switch (substr($operations, $j, 2))
			{
				case $this->OP_SMILIES:										// enable smilies in this segment
					$op[$this->OP_SMILIES] = TRUE;
					break;
				case $this->OP_LIST:										// enable lists in this segment
					$op[$this->OP_LIST] = TRUE;
					break;
				case $this->OP_REVERSE:
					$op[$this->OP_REVERSE] = TRUE;
					break;
				case $this->OP_SIMPLE:										// process simple markups in this segment
					$op[$this->OP_SIMPLE] = TRUE;
					break;
				case $this->OP_APPEARANCE:
					$op[$this->OP_APPEARANCE] = TRUE;
					break;
				case $this->OP_URLS:										// process urls in this segment
					$op[$this->OP_URLS] = TRUE;
					break;
				case $this->OP_MISC:										// miscelaneous markups in this segment
					$op[$this->OP_MISC] = TRUE;
					break;
				case $this->OP_PERSONAL:									// convert [me=XYZ] and [you] in this segment
					$op[$this->OP_PERSONAL] = TRUE;
					break;
				case $this->OP_IMAGES:										// enable images in this segment
					$op[$this->OP_IMAGES] = TRUE;
					break;
				case $this->OP_ALL:											// process all operations
					$op[$this->OP_NOHTML] = TRUE;
					$op[$this->OP_SMILIES] = TRUE;
					$op[$this->OP_PERSONAL] = TRUE;
					$op[$this->OP_SIMPLE] = TRUE;
					$op[$this->OP_APPEARANCE] = TRUE;
					$op[$this->OP_REVERSE] = TRUE;
					$op[$this->OP_CODE] = TRUE;
					$op[$this->OP_PHP] = ($this->_isPHP3 ? FALSE : TRUE);
					$op[$this->OP_QUOTE] = TRUE;
					$op[$this->OP_URLS] = TRUE;
					$op[$this->OP_LIST] = TRUE;
					$op[$this->OP_IMAGES] = TRUE;
					$op[$this->OP_MISC] = TRUE;
					$op[$this->OP_NBSP] = TRUE;
					$op[$this->OP_NL2BR] = TRUE;
					$j = $len;
					break;
				case $this->OP_NOHTML:										// disable all HTML
					$op[$this->OP_NOHTML] = TRUE;
					break;
				case $this->OP_SAFEHTML:									// disable only dangerous HTML
					$op[$this->OP_SAFEHTML] = TRUE;
					break;
				case $this->OP_NL2BR:										// convert newlines to <br>s in this segment
					$op[$this->OP_NL2BR] = TRUE;
					break;
				case $this->OP_NBSP:										// convert spaces and tabs to &nbsp; in this segment
					$op[$this->OP_NBSP] = TRUE;
					break;
				case $this->OP_QUOTE:										// There is no actual 'processing' of quotes,
					$op[$this->OP_QUOTE] = TRUE;
					break;
				case $this->OP_PHP:											// code and php code, as these
					$op[$this->OP_PHP] = TRUE;
					break;
				case $this->OP_CODE:										// segments require special treatment
					$op[$this->OP_CODE] = TRUE;
					break;
				default:													// ERROR!
					die("Parse error ($j: " . substr($operations, $j, 2) . ") - $operations!");
					break;
			}
		}


		if ($op[$this->OP_NOHTML])
		{
			$text = htmlentities($text);
			$expression = quotemeta("&amp;") . "([A-Z]+|" . quotemeta("#") . "[0-9]+);";
			$replacement = "&\\1;";
			$text = eregi_replace($expression, $replacement, $text);
		}
		else if ($op[$this->OP_SAFEHTML])
		{
			$text = str_replace("<!--", "&lt;!--", $text);
			$text = str_replace("-->", "--&gt;", $text);
			$text = preg_replace("!<((/)?((td|tr|table|th|script|meta|xmp|html|body|head|textarea)( .*)?)|([A-Z]+.*style=.*))>!Ui", "&lt;\\1&gt;", $text);
		}

		if ($op[$this->OP_LIST])											// enable lists in this segment
		{
			$expression = "!" . quotemeta("[list]") . "[\n\r]*?((" . quotemeta("[*]") . ".+)+)[\n\r]*?" .  quotemeta("[/list]") . "!Uis";
			if (!$this->_isPHP3)
			{
				$expression .= "e";
				$replacement = "\$this->_create_listitems('\\1')";
				$text = preg_replace($expression, $replacement, $text);
			}
			else
			{
				if (preg_match_all($expression, $text, $tmp))
				{
					reset($tmp[1]);
					while (list(, $var) = each($tmp[1]))
					{
						$exp = "!" . quotemeta("[list]") . "[\n\r]*?" . quotemeta($var) . "[\n\r]*?" .  quotemeta("[/list]") . "!Uis";
						$items = explode("[*]", $var);
						$tmp2 = "";
						for (reset($items); list(, $item) = each($items);)
							if (trim($item) != "")
								$tmp2 .= "<li>$item</li>";

						$text = preg_replace($exp, "<ul>$tmp2</ul>", $text);
					}
				}
			}
		}

		if ($op[$this->OP_SMILIES])											// enable smilies in this segment
			for (reset($this->_smilies); list($key, $value) = each($this->_smilies);)
				if ($key != "" && $value != "")
				{
					if ($op[$this->OP_NOHTML])
						$s = htmlspecialchars($key);
					else
						$s = $key;
					$text = str_replace($s, '<img src="' . $value . '" alt="' . $key . '">', $text);
				}

		if ($op[$this->OP_REVERSE])
			if (!$this->_isPHP3)
			{
				$expression =  "!" . quotemeta("[rev]") . "(.*)" . quotemeta("[/rev]") . "!Uise";
				$replacement = "strrev(\"\\1\")";
				$text = preg_replace($expression, $replacement, $text);
			}
			else
			{
				$expression =  "!(.*)" . quotemeta("[rev]") . "(.*?)" . quotemeta("[/rev]") . "(.*)!is";
				if (preg_match_all($expression, $text, $matches, PREG_SET_ORDER))
				{
					$count = count($matches);
					for ($k = 0; $k < $count; $k++)
						$text = $matches[$k][1] . strrev($matches[$k][2]) . $matches[$k][3];
				}
			}

		if ($op[$this->OP_SIMPLE])											// process simple markups in this segment
		{
		// VERY simple ;)
			$vars = array("b", "u", "i", "tt", "sub", "sup");

			$vars = implode("|", $vars);
			$oldText = $text . " ";

			while ($oldText != $text)
			{
				$oldText = $text;
				$text = preg_replace("!\[($vars)\](.+)\[/\\1\]!Uis", "<\\1>\\2</\\1>", $text);
			}

		// strike through
			$expression = "!" . quotemeta("[s]") . "(.+)" . quotemeta("[/s]") . "!Uis";
			$replacement = "<strike>\\1</strike>";
			$text = preg_replace($expression, $replacement, $text);

		// rulers
			$text = eregi_replace("\[hr\]", "<hr width='90%' align='left'>", $text);
		}
		
		if ($op[$this->OP_APPEARANCE])
		{
		// color
			$expression = "!" . quotemeta("[color=") . "(.+)" . quotemeta("]") . "(.+)" . quotemeta("[/color]") . "!Uis";
			$replacement = "<font color='\\1'>\\2</font>";
			$text = preg_replace($expression, $replacement, $text);

		// size
			$expression = "!" . quotemeta("[size=") . "(\d+)" . quotemeta("]") . "(.+)" . quotemeta("[/size]") . "!Uis";
			$replacement = "<font size='\\1'>\\2</font>";
			$text = preg_replace($expression, $replacement, $text);
		}

		if ($op[$this->OP_URLS])											// process urls in this segment
		{
			$expression = "!\\[email\\](.+)\\[/email\\]!Uis";
			$replacement = "<a href=\"mailto:\\1\">\\1</a>";
			$text = preg_replace($expression, $replacement, $text);

			$expression = "!\\[email=(.+)\\](.+)\\[/email\\]!Uis";
			$replacement = "<a href=\"mailto:\\1\">\\2</a>";
			$text = preg_replace($expression, $replacement, $text);

			//supplied by hide@address.com
			$text = preg_replace("!(\[url\])(.+)(\[/url\])!Uis", "<a href='\\2' target='_blank'>\\2</a>", $text); //for all links
			$text = preg_replace("!(\[url=)(http|https|ftp)(://\S+?)(\])(.+?)(\[/url\])!i", "<a href='\\2\\3' target='_blank'>\\5</a>", $text);//for http/https/ftp links
			$text = preg_replace("!(\[url=)(\S+?)(\])(.+?)(\[/url\])!i", "<a href='\\2' target='_blank'>\\4</a>", $text);//for other links

			//source: Mitchell Rietdijk / www.phpfreakz.com (customized by Arno van der Kolk)
			$text = eregi_replace("(^|[ \n\r\t])((http(s?)://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $text); 	//Hier worden alle http:// texten aanklikbare links.
			//$text = eregi_replace("(^|[ \n\r\t])((ftp://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href=\"\\2\" target=\"_blank\">\\2</a>", $text); 	//Hier worden alle ftp:// texten aanklikbare links.
			$text = preg_replace("!(^|[ \n\r\t])((ftp://)(([a-z0-9_-]+)(:([a-z0-9_-]+([a-z0-9_-]+\@)?))?\@)?(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)!i", "\\1<a href='\\2'>\\2</a>", $text);
			$text = eregi_replace("(^|[ \n\r\t])([a-z_-][a-z0-9\._-]*@[a-z0-9_-]+(\.[a-z0-9_-]+)+)", "\\1<a href='mailto:\\2'>\\2</a>", $text); 	//Hier worden e-mail adressen aanklikbaar
			$text = eregi_replace("(^|[ \n\r\t])(www\.([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href='http://\\2' target='_blank'>\\2</a>", $text); 	//Als iemand de http:// vergeet en met www. begint wordt automatisch http:// toegevoegd en aanklikbaar gemaakt.
			$text = eregi_replace("(^|[ \n\r\t])(ftp\.([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*)", "\\1<a href='ftp://\\2' target='_blank'>\\2</a>", $text); 	//Als iemand de ftp:// vergeet en met ftp. begint wordt automatisch ftp:// toegevoegd en aanklikbaar gemaakt.
		}

		if ($op[$this->OP_MISC])											// miscelaneous markups in this segment
		{
			$expression = "!\\[(off( )?topic)\\][\n\r]*?(.*)[\n\r]*?\\[/\\1\\]!Uis";
			$replacement = "<small>\\1:<br>\\3<br></small>";
			$text = preg_replace($expression, $replacement, $text);

			$expression = "!\\[edit\\][\n\r]*?(.*)[\n\r]*?\\[/edit\\]!Uis";
			$replacement = $this->lang['edit'] . ":<br><i>\\1</i>";
			$text = preg_replace($expression, $replacement, $text);
		}

		if ($op[$this->OP_PERSONAL])										// convert [me=XYZ] and [you] in this segment
		{
			$you = ( ! empty( $this->_reader ) ) ? $this->_reader : $this->lang['guest'] ;

			$expression = "!\[me=(.*)\]((.|\n|\r)*)\[/me\]!Ui";				// do not use 's' modifier because \\1 must NOT be multiline
			$replacement = "<span style='display: block' class='me'>» \\1 \\2</span>";
			$text = preg_replace($expression, $replacement, $text);

			$expression = "!" . quotemeta("[you]") . "!i";
			$replacement = "<span class='you'>$you</span>";
			$text = preg_replace($expression, $replacement, $text);
		}

		if ($op[$this->OP_IMAGES])											// enable images in this segment
		{
			//not recommended: (automagically insert pictures wherever their URLs appear)
//			$text = eregi_replace("(^|[ \n\r\t])((http(s?)://)(www\.)?([a-z0-9_-]+(\.[a-z0-9_-]+)+)(/[^/ \n\r]*)*(\.jpg|\.gif))","\\1<img src=\"\\2\">",$text); 	//Hier worden alle http:// texten aanklikbare links.

			//supplied by hide@address.com
			$text = preg_replace(
						"!\[img\](.+?)\[/img\]!is",
						"<img alt='" . $this->lang['image'] . ": \\1' src='\\1' border='0'>",
						$text
					); //for [img]

			$expression = "!\[img2\](.+?)\[/img2\]!i";

			// This is a bit buggy when \ and ' are in the URL, but normally that does not happen anyway:
			$replacement = $this->_encapsulate('image', "<center><a href='\\1' target='viewPicture'><img border='0' src='" . $this->_imgURL . "icon.gif' alt='" . $this->lang['image'] . ": \\1'></a></center>");

			$text = preg_replace($expression, $replacement, $text);
		}

		if ($op[$this->OP_NL2BR])											// now convert newlines
			$text = nl2br($text);

		if ($op[$this->OP_NBSP])											// now convert spaces and tabs
		{
			$text = str_replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;", $text);	// tabs are 4 spaces; you might just as well make it 8 :)
			$text = str_replace("  ", "&nbsp; ", $text);					// do not convert to "&nbsp;&nbsp;" for the sake of word wrapping
		}

		unset($op);
		return $text;
	} // end func _processNormal


	/**
	* Searches for a specific operator in a sequence of operations. (Called by <code>_processNormal()</code>)
	*
	* You should not call this function directly. But since it's a static, it could not
	* possibly do any harm. :)
	*
	* @access	private
	* @static
	* @param	string	$sequence	Sequence of operations to be searched
	* @param	string	$operator	Operator to search for
	* @return	boolean				TRUE represents found, FALSE represents not found
	* @see		_processNormal()
	* @since	2.14
	*/
	function _has_operator($sequence, $operator)
	{
		$pos = strpos($sequence, $operator);
		if ($pos % 2 == 0)
		{
			if ($pos > 0 || substr($sequence, 0, 2) == $operator)
				return true;
		}
		return false;
	} // end func _has_operator


	/**
	* Create the listitems for a list (called from <code>_processNormal()</code>).
	*
	* You should not call this function directly. But since it's a static, it could not
	* possibly do any harm. :)
	*
	* @access	private
	* @static
	* @param	string	$items				string represents the list of list-items
	* @return	string						A comlete HTML list
	* @see		_processNormal(), $OP_LIST
	* @since	2.0
	*/
	function _create_listitems($items)
	{
		$items = explode("[*]", $items);
		$count = count($items);
		for ($i = 0; $i < $count; $i++)
		{
			$items[$i] = trim($items[$i]);
			if ($items[$i] != "")
				$items[$i] = "<li>" . $items[$i] . "</li>";
		}
		return str_replace("\'", "'", "<ul>" . implode("", $items) . "</ul>");
	} // end func _create_listitems


	/**
	* Re-assembles all the segments and returns the resulting text
	*
	* This function is normally called after the <code>parse</code> method has been called.
	* Otherwise the original text will just be returned, unmodified.
	*
	* @access	public
	* @return	string		The text (either parsed or not) represented by this instance
	* @brother	pgetText()
	* @since	1.0
	*/
	function getText()
	{
		return implode("", $this->_segments);
	} // end func getText


	/**
	* Parses and returns the text
	*
	* This function transitively calls the <code>parse</code> method and afterwards
	* <code>getText</code> to return the result.
	*
	* @access	public
	* @param	string	$operations		Operations to perform on the represented text
	* @return	string					The parsed text represented by this instance
	* @brother	getText()
	* @see		parse()
	* @since	2.0
	*/
	function pgetText($operations)
	{
		$this->parse($operations);
		return $this->getText();
	} // end func pgetText


	/**
	* Puts the specified text in a HTML box along with a caption
	*
	* Please see the source of this function to see what the exact result will be. If
	* necessesary, you can also edit that html source to alter the results produced by
	* this function.
	*
	* @access	private
	* @static
	* @param	string	$caption	Caption of the new html box (will be retrieved from the language data, using <code>$caption</code> as key)
	* @param	string	$text		Text to put into the html box
	* @return	string				Text encapsulated in a html box
	* @see		_processTypes()
	* @since	2.0
	*/
	function _encapsulate($caption, $text)
	{
		// create an appropriate seperator:
		$sep = ( $this->_imgURL ?
				"<td height='1'><img width='1' height='1' src='" . $this->_imgURL . "pixel.gif' alt=''>" :	// use either an image (1x1) (more compatible)
				"<td height='1'>" )																// or some advanced TD attribute

				. "</td>";																		// close cell off

		// create the actual HTML box:
		$tmp =	"<blockquote>" .
					"<table width='80%' cellpadding='0' cellspacing='0'>" .
						"<tr>" .
							"<td><small>" . $this->lang[$caption] . ":</small></td>" .
						"</tr>" .
						"<tr bgcolor='#000000' height='1'>" .
							$sep .
						"</tr>" .
						"<tr class='$caption'>" .
							"<td" . ($caption == 'code' ? " nowrap style='white-space: nowrap'" : "") . ">" .
								str_replace("\'", "'", $text) .
							"</td>" .
						"</tr>" .
						"<tr bgcolor='#000000' height='1'>" .
							$sep .
						"</tr>" .
					"</table>" .
				"</blockquote>";

		unset($sep);
		return $tmp;
	} // end func _encapsulate


	/**
	* Auxilary function for the PHP4 impaired
	*
	* This is a re-implementation of <code>highlight_string</code>.
	*
	*
	* Original information:
	*	(Source: http://www.phpbuilder.com/tips/item.php?id=216)
	*
	*	Program name : Colorizator v1.0
	*	Author       : Alexander Yanuar Koentjara
	*	               hide@address.com
	*	Purpose      : To make php code become a colorful HTML page !!
	*
	* @access	private
	* @static
	* @param	string	$text									String to highlight
	* @return	string											The highlighted string
	* @see		_highlight_parse()								Auxilary function
	* @link		http://www.php.net/highlight_string				PHP4 function highlight_string on www.php.net
	* @link		http://www.phpbuilder.com/tips/item.php?id=216	Original location of source
	* @since	2.9
	* @todo														Fix the bug which causes the last / of /x x/ blocks (where 'x' is a '*') to appear in normal font
	*/
	function highlightstring($text)
	{
		$result = "";

		$CODE_BEGIN	= "<" . "?";	// sorry ... so it will not caught by Colorizator
		$CODE_END	= "?" . ">";	// sorry ... so it will not caught by Colorizator

		$arr_RESERVED_WORD = array("if", "while", "for", "return", "else");
		$arr_DECLARATION_WORD = array("class", "var", "function", "global", "GLOBAL");

		$color_RESERVED_WORD = "RED";
		$color_DECLARATION_WORD = "BLUE";
		$color_COMMENT = "#707090";
		$color_DEFAULT = "#3333aa";
		$color_STRING = "#800000";
		$color_VARIABLE = "GREEN";
		$color_HTML = "BLACK";

		// The following 2 have to be 'random' strings, that cannot not occur in the text
		$splitter	= "|X*-(LexZ)-*X|" . time();
		$splitter2	= "|X*-(Kick)-*X|" . time();

		$RESERVED_WORD = implode("|", $arr_RESERVED_WORD);
		$DECLARATION_WORD = implode("|", $arr_DECLARATION_WORD);

		$result .=
			"<PRE>
			<!--
				This php code is converted into HTML using :

				Colorizator v1.0 (c) 2001 by Alexander Yanuar Koentjara (hide@address.com)

			-->\n";


		$result .= "<FONT FACE='Courier New' color='$color_DEFAULT'>";

		$delimiter = array(
						0		=> 0,
						"//"	=> array(2, "[\r\n]", $color_COMMENT),
						"\""	=> array(1, "\"", $color_STRING),
						"'"		=> array(1, "'", $color_STRING),
						"/*"	=> array(2, "\*/", $color_COMMENT),
						"#"		=> array(1, "[\r\n]", $color_COMMENT)
					);

		$pos1 = 0;
		$pos2 = 0;

		while(1)
		{
			$posx = strpos(" $text", $CODE_BEGIN);
			if (!$posx && strlen($text) > 0)
				$posx = strlen($text) + 1;
			if ($posx)
			{
				$posx--;
				$result .= "<FONT COLOR='$color_HTML'>" . htmlspecialchars(substr($text, 0, $posx)) . "</FONT>";
			}

			if (!strpos(" $text", $CODE_BEGIN))
				break;
			$pos1 = strpos("$text", "$CODE_BEGIN") + 2;

			$pos2 = strpos($text, "$CODE_END") - 1;
			if ($pos2 < 1)
				$pos2 = strlen($text) - 1;

			$result .= "&lt;?";
			$str = substr($text, $pos1, $pos2 - $pos1 + 1);
//			$result .= $this->_highlight_parse($str);
			$result .= $this->_highlight_parse($str, $delimiter, $splitter, $splitter2, $color_VARIABLE, $RESERVED_WORD, $DECLARATION_WORD, $color_RESERVED_WORD, $color_DECLARATION_WORD);

			$result .= "?&gt;";
			$text = substr($text, $pos2 + 3);
		}

		$result .= "</FONT></PRE>";

		return $result;
	} // end func highlightstring


	/**
	* Auxilary function for the PHP4 impaired
	*
	* This function is for continued program flow from <code>highlightstring()</code>.
	* It actually highlights strings
	*
	*
	* Original information:
	*	(Source: http://www.phpbuilder.com/tips/item.php?id=216)
	*
	*	Program name : Colorizator v1.0
	*	Author       : Alexander Yanuar Koentjara
	*	               hide@address.com
	*	Purpose      : To make php code become a colorful HTML page !!
	*
	* @access	private
	* @static
	* @param	string	$str					String to parse
	* @param	array	$delimiter				Array of delimiters
	* @param	string	$splitter				Line break delimiter
	* @param	string	$splitter2				Line break delimiter
	* @param	string	$color_VARIABLE			Part of a regexp
	* @param	string	$RESERVED_WORD			Part of a regexp
	* @param	string	$DECLARATION_WORD		Part of a regexp
	* @param	string	$color_RESERVED_WORD	Part of a regexp
	* @param	string	$color_DECLARATION_WORD	Part of a regexp
	* @return	string							The parsed string
	* @see		highlightstring()				Calling function
	* @since	2.9
	* @todo										Speed the darned thing up :)
	*/
	function _highlight_parse($str, $delimiter, $splitter, $splitter2, $color_VARIABLE, $RESERVED_WORD, $DECLARATION_WORD, $color_RESERVED_WORD, $color_DECLARATION_WORD)
	{
		//if (floor(phpversion()) < 4)
		//	return htmlspecialchars($str);

		$flag = 0;
		$pos2 = -1;
		$all = "";
		$strlen = strlen($str);

		while ($pos2 < $strlen - 1)
		{
			$pos2++;
			if ($flag)
			{
				$flag2 = 1;
				if (substr($str, $pos2 - 1, 1) == "\\") $flag2 = 0;
				if (substr($str, $pos2 - 2, 2) == "\\\\") $flag2 = 1;

				if (ereg($delimiter[$flag][1], substr($str, $pos2, $delimiter[$flag][0])) && $flag2)
				{
					$all .= htmlspecialchars(substr($str, $pos2, 1)) . "$splitter2</FONT>";
					$flag = 0;
				}
				else
					$all .= htmlspecialchars(substr($str, $pos2, 1));
			}
			else
			{
				reset($delimiter);
				while (list($key, $val) = each($delimiter))
				{
					if ($key)
					{
						if (substr($str, $pos2, $val[0]) == $key)
						{
							$all .= "<FONT COLOR='$val[2]'>$splitter" . htmlspecialchars(substr($str, $pos2, $val[0]));
							$pos2 += ($val[0] - 1);
							$flag = $key;
							break;
						}
					}
				}
				if (!$flag)
					$all .= htmlspecialchars(substr($str, $pos2, 1));
			}
		}

		$all = eregi_replace(
					"(\\\$[a-z0-9_]+)",
					"<FONT COLOR='$color_VARIABLE'>\\1</FONT>",
					$all
				);

		$all = ereg_replace(
//					"([\r\n \t{};])($RESERVED_WORD)([\r\n \t{};])",
					"([\r\n \t{};(),])($RESERVED_WORD)([\r\n \t{};(),])",
					"\\1<FONT COLOR='$color_RESERVED_WORD'>\\2</FONT>\\3",
					$all
				);

		$all = ereg_replace(
//					"([\r\n \t{};])($DECLARATION_WORD)([\r\n \t{};])",
					"([\r\n \t{};(),])($DECLARATION_WORD)([\r\n \t{};(),])",
					"\\1<I><FONT COLOR='$color_DECLARATION_WORD'>\\2</FONT></I>\\3",
					$all
				);

		$text = explode($splitter, $all);
		$all = "";

		$count = count($text);
		if ($count > 1)
			for ($i = 0; $i < $count; $i++)
			{
				$text2 = explode($splitter2, $text[$i]);
				if (count($text2) > 1)
				{
					$text2[0] = eregi_replace(
									"(<[/]{0,1}FONT[^>]*>|<[/]{0,1}B>|<[/]{0,1}I>)",
									"",
									$text2[0]
								);
					$all .= $text2[0] . $text2[1];
				}
				else
					$all .= $text[$i];
			}
		else
			$all = join("", $text);

		return $all;
	} // end func _highlight_parse


	/**
	* Auxilary function for the PHP4 impaired
	*
	* Emulated PHP4's <code>array_keys</code> function
	*
	* @access	private
	* @static
	* @param	array	$arr					Contains elements to be searched
	* @param	string	$term					Contains search term
	* @return	array							All found items
	* @link		http://www.php.net/array_keys	array_keys on www.php.net
	* @since	2.10
	*/
	function arraykeys($arr, $term = "")
	{
		if (!function_exists("array_keys"))
		{
			$t = array();
			while (list($k,$v) = each($arr)) {
				if ($term && $v != $term)
					continue;
				$t[] = $k;
			}
			return $t;
		}
		else if ($term != "")
			return array_keys($arr, $term);
		else
			return array_keys($arr);
	} // end func arraykeys


	/**
	* Auxilary function for the PHP4 impaired
	*
	* Emulated PHP4's <code>array_values</code> function
	*
	* @access	private
	* @static
	* @param	array	$arr					Contains elements to be searched
	* @return	array							All found items
	* @link		http://www.php.net/array_values	array_values on www.php.net
	* @since	2.10
	*/
	function arrayvalues($arr)
	{
		if (!function_exists("array_values"))
		{
			$t = array();
			while (list($k, $v) = each ($arr))
				$t[] = $v;
			return $t;
		}
		else
			return array_values($arr);
	} // end func arrayvalues

}
?>
Return current item: YBBtags