added ability to "extend" helpers
* modified Loader to check for prefixed helpers in application/helpers folder
* surrounded provided helper functions with if (! function_exists('foo')) conditionals so the user's helper functions take precedent.
diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php
index 20bf323..30cec31 100644
--- a/system/helpers/text_helper.php
+++ b/system/helpers/text_helper.php
@@ -38,27 +38,30 @@
  * @param	string	the end character. Usually an ellipsis

  * @return	string

  */	

-function word_limiter($str, $n = 100, $end_char = '…')

+if (! function_exists('word_limiter'))

 {

-	if (strlen($str) < $n)

+	function word_limiter($str, $n = 100, $end_char = '&#8230;')

 	{

-		return $str;

-	}

+		if (strlen($str) < $n)

+		{

+			return $str;

+		}

 	

-	$words = explode(' ', preg_replace("/\s+/", ' ', preg_replace("/(\r\n|\r|\n)/", " ", $str)));

+		$words = explode(' ', preg_replace("/\s+/", ' ', preg_replace("/(\r\n|\r|\n)/", " ", $str)));

 	

-	if (count($words) <= $n)

-	{

-		return $str;

-	}

+		if (count($words) <= $n)

+		{

+			return $str;

+		}

 			

-	$str = '';

-	for ($i = 0; $i < $n; $i++)

-	{

-		$str .= $words[$i].' ';

-	}

+		$str = '';

+		for ($i = 0; $i < $n; $i++)

+		{

+			$str .= $words[$i].' ';

+		}

 

-	return trim($str).$end_char;

+		return trim($str).$end_char;

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -75,28 +78,31 @@
  * @param	string	the end character. Usually an ellipsis

  * @return	string

  */	

-function character_limiter($str, $n = 500, $end_char = '&#8230;')

+if (! function_exists('character_limiter'))

 {

-	if (strlen($str) < $n)

+	function character_limiter($str, $n = 500, $end_char = '&#8230;')

 	{

-		return $str;

-	}

-		

-	$str = preg_replace("/\s+/", ' ', preg_replace("/(\r\n|\r|\n)/", " ", $str));

-

-	if (strlen($str) <= $n)

-	{

-		return $str;

-	}

-									

-	$out = "";

-	foreach (explode(' ', trim($str)) as $val)

-	{

-		$out .= $val.' ';			

-		if (strlen($out) >= $n)

+		if (strlen($str) < $n)

 		{

-			return trim($out).$end_char;

-		}		

+			return $str;

+		}

+		

+		$str = preg_replace("/\s+/", ' ', preg_replace("/(\r\n|\r|\n)/", " ", $str));

+

+		if (strlen($str) <= $n)

+		{

+			return $str;

+		}

+									

+		$out = "";

+		foreach (explode(' ', trim($str)) as $val)

+		{

+			$out .= $val.' ';			

+			if (strlen($out) >= $n)

+			{

+				return trim($out).$end_char;

+			}		

+		}

 	}

 }

 	

@@ -111,41 +117,44 @@
  * @param	string

  * @return	string

  */	

-function ascii_to_entities($str)

+if (! function_exists('ascii_to_entities'))

 {

-   $count	= 1;

-   $out	= '';

-   $temp	= array();

+	function ascii_to_entities($str)

+	{

+	   $count	= 1;

+	   $out	= '';

+	   $temp	= array();

 	

-   for ($i = 0, $s = strlen($str); $i < $s; $i++)

-   {

-	   $ordinal = ord($str[$i]);

+	   for ($i = 0, $s = strlen($str); $i < $s; $i++)

+	   {

+		   $ordinal = ord($str[$i]);

 	

-	   if ($ordinal < 128)

-	   {

-		   $out .= $str[$i];

-	   }

-	   else

-	   {

-		   if (count($temp) == 0)

+		   if ($ordinal < 128)

 		   {

-			   $count = ($ordinal < 224) ? 2 : 3;

+			   $out .= $str[$i];

 		   }

-		

-		   $temp[] = $ordinal;

-		

-		   if (count($temp) == $count)

+		   else

 		   {

-			   $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);

+			   if (count($temp) == 0)

+			   {

+				   $count = ($ordinal < 224) ? 2 : 3;

+			   }

+		

+			   $temp[] = $ordinal;

+		

+			   if (count($temp) == $count)

+			   {

+				   $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64);

 

-			   $out .= '&#'.$number.';';

-			   $count = 1;

-			   $temp = array();

+				   $out .= '&#'.$number.';';

+				   $count = 1;

+				   $temp = array();

+			   }

 		   }

 	   }

-   }

 

-   return $out;

+	   return $out;

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -160,45 +169,48 @@
  * @param	bool

  * @return	string

  */	

-function entities_to_ascii($str, $all = TRUE)

+if (! function_exists('entities_to_ascii'))

 {

-   if (preg_match_all('/\&#(\d+)\;/', $str, $matches))

-   {

-	   for ($i = 0, $s = count($matches['0']); $i < $s; $i++)

-	   {				

-		   $digits = $matches['1'][$i];

+	function entities_to_ascii($str, $all = TRUE)

+	{

+	   if (preg_match_all('/\&#(\d+)\;/', $str, $matches))

+	   {

+		   for ($i = 0, $s = count($matches['0']); $i < $s; $i++)

+		   {				

+			   $digits = $matches['1'][$i];

 

-		   $out = '';

+			   $out = '';

 

-		   if ($digits < 128)

-		   {

-			   $out .= chr($digits);

+			   if ($digits < 128)

+			   {

+				   $out .= chr($digits);

 		

-		   }

-		   elseif ($digits < 2048)

-		   {

-			   $out .= chr(192 + (($digits - ($digits % 64)) / 64));

-			   $out .= chr(128 + ($digits % 64));

-		   }

-		   else

-		   {

-			   $out .= chr(224 + (($digits - ($digits % 4096)) / 4096));

-			   $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64));

-			   $out .= chr(128 + ($digits % 64));

-		   }

+			   }

+			   elseif ($digits < 2048)

+			   {

+				   $out .= chr(192 + (($digits - ($digits % 64)) / 64));

+				   $out .= chr(128 + ($digits % 64));

+			   }

+			   else

+			   {

+				   $out .= chr(224 + (($digits - ($digits % 4096)) / 4096));

+				   $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64));

+				   $out .= chr(128 + ($digits % 64));

+			   }

 

-		   $str = str_replace($matches['0'][$i], $out, $str);				

+			   $str = str_replace($matches['0'][$i], $out, $str);				

+		   }

 	   }

-   }

 

-   if ($all)

-   {

-	   $str = str_replace(array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#45;"),

-						  array("&","<",">","\"", "'", "-"),

-						  $str);

-   }

+	   if ($all)

+	   {

+		   $str = str_replace(array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#45;"),

+							  array("&","<",">","\"", "'", "-"),

+							  $str);

+	   }

 

-   return $str;

+	   return $str;

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -216,27 +228,30 @@
  * @param	string	the optional replacement value

  * @return	string

  */	

-function word_censor($str, $censored, $replacement = '')

+if (! function_exists('word_censor'))

 {

-	if ( ! is_array($censored))

+	function word_censor($str, $censored, $replacement = '')

 	{

-		return $str;

-	}

+		if ( ! is_array($censored))

+		{

+			return $str;

+		}

 

-	$str = ' '.$str.' ';

-	foreach ($censored as $badword)

-	{

-		if ($replacement != '')

+		$str = ' '.$str.' ';

+		foreach ($censored as $badword)

 		{

-			$str = preg_replace("/\b(".str_replace('\*', '\w*?', preg_quote($badword)).")\b/i", $replacement, $str);

+			if ($replacement != '')

+			{

+				$str = preg_replace("/\b(".str_replace('\*', '\w*?', preg_quote($badword)).")\b/i", $replacement, $str);

+			}

+			else

+			{

+				$str = preg_replace("/\b(".str_replace('\*', '\w*?', preg_quote($badword)).")\b/ie", "str_repeat('#', strlen('\\1'))", $str);

+			}

 		}

-		else

-		{

-			$str = preg_replace("/\b(".str_replace('\*', '\w*?', preg_quote($badword)).")\b/ie", "str_repeat('#', strlen('\\1'))", $str);

-		}

-	}

 	

-	return trim($str);

+		return trim($str);

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -250,45 +265,48 @@
  * @param	string	the text string

  * @return	string

  */	

-function highlight_code($str)

-{		

-	// The highlight string function encodes and highlights

-	// brackets so we need them to start raw

-	$str = str_replace(array('&lt;', '&gt;'), array('<', '>'), $str);

+if (! function_exists('highlight_code'))

+{

+	function highlight_code($str)

+	{		

+		// The highlight string function encodes and highlights

+		// brackets so we need them to start raw

+		$str = str_replace(array('&lt;', '&gt;'), array('<', '>'), $str);

 	

-	// Replace any existing PHP tags to temporary markers so they don't accidentally

-	// break the string out of PHP, and thus, thwart the highlighting.

+		// Replace any existing PHP tags to temporary markers so they don't accidentally

+		// break the string out of PHP, and thus, thwart the highlighting.

 	

-	$str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'), 

-						array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str);

+		$str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'), 

+							array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str);

 

-	// The highlight_string function requires that the text be surrounded

-	// by PHP tags.  Since we don't know if A) the submitted text has PHP tags,

-	// or B) whether the PHP tags enclose the entire string, we will add our

-	// own PHP tags around the string along with some markers to make replacement easier later

+		// The highlight_string function requires that the text be surrounded

+		// by PHP tags.  Since we don't know if A) the submitted text has PHP tags,

+		// or B) whether the PHP tags enclose the entire string, we will add our

+		// own PHP tags around the string along with some markers to make replacement easier later

 	

-	$str = '<?php tempstart'."\n".$str.'tempend ?>';

+		$str = '<?php tempstart'."\n".$str.'tempend ?>';

 	

-	// All the magic happens here, baby!

-	$str = highlight_string($str, TRUE);

+		// All the magic happens here, baby!

+		$str = highlight_string($str, TRUE);

 

-	// Prior to PHP 5, the highlight function used icky font tags

-	// so we'll replace them with span tags.	

-	if (abs(phpversion()) < 5)

-	{

-		$str = str_replace(array('<font ', '</font>'), array('<span ', '</span>'), $str);

-		$str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str);

-	}

+		// Prior to PHP 5, the highlight function used icky font tags

+		// so we'll replace them with span tags.	

+		if (abs(phpversion()) < 5)

+		{

+			$str = str_replace(array('<font ', '</font>'), array('<span ', '</span>'), $str);

+			$str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str);

+		}

 	

-	// Remove our artificially added PHP

-	$str = preg_replace("#\<code\>.+?tempstart\<br />(?:\</span\>)?#is", "<code>\n", $str);

-	$str = preg_replace("#tempend.+#is", "</span>\n</code>", $str);	

+		// Remove our artificially added PHP

+		$str = preg_replace("#\<code\>.+?tempstart\<br />(?:\</span\>)?#is", "<code>\n", $str);

+		$str = preg_replace("#tempend.+#is", "</span>\n</code>", $str);	

 	

-	// Replace our markers back to PHP tags.

-	$str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),

-						array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'), $str);

+		// Replace our markers back to PHP tags.

+		$str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'),

+							array('&lt;?', '?&gt;', '&lt;%', '%&gt;', '\\', '&lt;/script&gt;'), $str);

 										

-	return $str;

+		return $str;

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -305,19 +323,22 @@
  * @param	string	the closing tag to end the phrase with

  * @return	string

  */	

-function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>')

+if (! function_exists('highlight_phrase'))

 {

-	if ($str == '')

+	function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>')

 	{

-		return '';

-	}

+		if ($str == '')

+		{

+			return '';

+		}

 	

-	if ($phrase != '')

-	{

-		return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str);

-	}

+		if ($phrase != '')

+		{

+			return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str);

+		}

 

-	return $str;

+		return $str;

+	}

 }

 	

 // ------------------------------------------------------------------------

@@ -334,89 +355,91 @@
  * @param	integer	the number of characters to wrap at

  * @return	string

  */	

-function word_wrap($str, $charlim = '76')

+if (! function_exists('word_wrap'))

 {

-	// Se the character limit

-	if ( ! is_numeric($charlim))

-		$charlim = 76;

-	

-	// Reduce multiple spaces

-	$str = preg_replace("| +|", " ", $str);

-	

-	// Standardize newlines

-	$str = preg_replace("/\r\n|\r/", "\n", $str);

-	

-	// If the current word is surrounded by {unwrap} tags we'll 

-	// strip the entire chunk and replace it with a marker.

-	$unwrap = array();

-	if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))

+	function word_wrap($str, $charlim = '76')

 	{

-		for ($i = 0; $i < count($matches['0']); $i++)

-		{

-			$unwrap[] = $matches['1'][$i];				

-			$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);

-		}

-	}

+		// Se the character limit

+		if ( ! is_numeric($charlim))

+			$charlim = 76;

 	

-	// Use PHP's native function to do the initial wordwrap.  

-	// We set the cut flag to FALSE so that any individual words that are 

-	// too long get left alone.  In the next step we'll deal with them.

-	$str = wordwrap($str, $charlim, "\n", FALSE);

+		// Reduce multiple spaces

+		$str = preg_replace("| +|", " ", $str);

 	

-	// Split the string into individual lines of text and cycle through them

-	$output = "";

-	foreach (explode("\n", $str) as $line) 

-	{

-		// Is the line within the allowed character count?

-		// If so we'll join it to the output and continue

-		if (strlen($line) <= $charlim)

+		// Standardize newlines

+		$str = preg_replace("/\r\n|\r/", "\n", $str);

+	

+		// If the current word is surrounded by {unwrap} tags we'll 

+		// strip the entire chunk and replace it with a marker.

+		$unwrap = array();

+		if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))

 		{

-			$output .= $line."\n";			

-			continue;

-		}

-			

-		$temp = '';

-		while((strlen($line)) > $charlim) 

-		{

-			// If the over-length word is a URL we won't wrap it

-			if (preg_match("!\[url.+\]|://|wwww.!", $line))

+			for ($i = 0; $i < count($matches['0']); $i++)

 			{

-				break;

+				$unwrap[] = $matches['1'][$i];				

+				$str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);

+			}

+		}

+	

+		// Use PHP's native function to do the initial wordwrap.  

+		// We set the cut flag to FALSE so that any individual words that are 

+		// too long get left alone.  In the next step we'll deal with them.

+		$str = wordwrap($str, $charlim, "\n", FALSE);

+	

+		// Split the string into individual lines of text and cycle through them

+		$output = "";

+		foreach (explode("\n", $str) as $line) 

+		{

+			// Is the line within the allowed character count?

+			// If so we'll join it to the output and continue

+			if (strlen($line) <= $charlim)

+			{

+				$output .= $line."\n";			

+				continue;

+			}

+			

+			$temp = '';

+			while((strlen($line)) > $charlim) 

+			{

+				// If the over-length word is a URL we won't wrap it

+				if (preg_match("!\[url.+\]|://|wwww.!", $line))

+				{

+					break;

+				}

+

+				// Trim the word down

+				$temp .= substr($line, 0, $charlim-1);

+				$line = substr($line, $charlim-1);

+			}

+		

+			// If $temp contains data it means we had to split up an over-length 

+			// word into smaller chunks so we'll add it back to our current line

+			if ($temp != '')

+			{

+				$output .= $temp . "\n" . $line; 

+			}

+			else

+			{

+				$output .= $line;

 			}

 

-			// Trim the word down

-			$temp .= substr($line, 0, $charlim-1);

-			$line = substr($line, $charlim-1);

-		}

-		

-		// If $temp contains data it means we had to split up an over-length 

-		// word into smaller chunks so we'll add it back to our current line

-		if ($temp != '')

-		{

-			$output .= $temp . "\n" . $line; 

-		}

-		else

-		{

-			$output .= $line;

+			$output .= "\n";

 		}

 

-		$output .= "\n";

+		// Put our markers back

+		if (count($unwrap) > 0)

+		{	

+			foreach ($unwrap as $key => $val)

+			{

+				$output = str_replace("{{unwrapped".$key."}}", $val, $output);

+			}

+		}

+

+		// Remove the unwrap tags

+		$output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output);

+

+		return $output;	

 	}

-

-	// Put our markers back

-	if (count($unwrap) > 0)

-	{	

-		foreach ($unwrap as $key => $val)

-		{

-			$output = str_replace("{{unwrapped".$key."}}", $val, $output);

-		}

-	}

-

-	// Remove the unwrap tags

-	$output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output);

-

-	return $output;	

 }

- 

 

 ?>
\ No newline at end of file