Index: wp-includes/plugin.php
===================================================================
--- wp-includes/plugin.php	(revision 15570)
+++ wp-includes/plugin.php	(working copy)
@@ -65,8 +65,9 @@
 function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
 	global $wp_filter, $merged_filters;
 
-	$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
-	$wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
+	$accepted_args = max(0, (int) $accepted_args );
+	$unique_id     = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
+	$wp_filter[$tag][$priority][$unique_id] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
 	unset( $merged_filters[ $tag ] );
 	return true;
 }
@@ -86,17 +87,18 @@
 function has_filter($tag, $function_to_check = false) {
 	global $wp_filter;
 
-	$has = !empty($wp_filter[$tag]);
-	if ( false === $function_to_check || false == $has )
-		return $has;
+	if ( empty( $wp_filter[$tag] ) )
+		return false;
 
-	if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) )
+	if ( false === $function_to_check )
+		return true;
+
+	if ( !( $unique_id = _wp_filter_build_unique_id( $tag, $function_to_check, false ) ) ) 
 		return false;
 
-	foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) {
-		if ( isset($wp_filter[$tag][$priority][$idx]) )
+	foreach ( array_keys( $wp_filter[$tag] ) as $priority )
+		if ( isset( $wp_filter[$tag][$priority][$unique_id] ) )
 			return $priority;
-	}
 
 	return false;
 }
@@ -132,45 +134,9 @@
  * @return mixed The filtered value after all hooked functions are applied to it.
  */
 function apply_filters($tag, $value) {
-	global $wp_filter, $merged_filters, $wp_current_filter;
-
-	$args = array();
-	$wp_current_filter[] = $tag;
-
-	// Do 'all' actions first
-	if ( isset($wp_filter['all']) ) {
-		$args = func_get_args();
-		_wp_call_all_hook($args);
-	}
-
-	if ( !isset($wp_filter[$tag]) ) {
-		array_pop($wp_current_filter);
-		return $value;
-	}
-
-	// Sort
-	if ( !isset( $merged_filters[ $tag ] ) ) {
-		ksort($wp_filter[$tag]);
-		$merged_filters[ $tag ] = true;
-	}
-
-	reset( $wp_filter[ $tag ] );
-
-	if ( empty($args) )
-		$args = func_get_args();
-
-	do {
-		foreach( (array) current($wp_filter[$tag]) as $the_ )
-			if ( !is_null($the_['function']) ){
-				$args[1] = $value;
-				$value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
-			}
-
-	} while ( next($wp_filter[$tag]) !== false );
-
-	array_pop( $wp_current_filter );
-
-	return $value;
+	$args = func_get_args();
+	$tag  = array_shift( $args );
+	return _wp_call_hook(true, $tag, $args);
 }
 
 /**
@@ -191,39 +157,7 @@
  * @return mixed The filtered value after all hooked functions are applied to it.
  */
 function apply_filters_ref_array($tag, $args) {
-	global $wp_filter, $merged_filters, $wp_current_filter;
-
-	$wp_current_filter[] = $tag;
-
-	// Do 'all' actions first
-	if ( isset($wp_filter['all']) ) {
-		$all_args = func_get_args();
-		_wp_call_all_hook($all_args);
-	}
-
-	if ( !isset($wp_filter[$tag]) ) {
-		array_pop($wp_current_filter);
-		return $args[0];
-	}
-
-	// Sort
-	if ( !isset( $merged_filters[ $tag ] ) ) {
-		ksort($wp_filter[$tag]);
-		$merged_filters[ $tag ] = true;
-	}
-
-	reset( $wp_filter[ $tag ] );
-
-	do {
-		foreach( (array) current($wp_filter[$tag]) as $the_ )
-			if ( !is_null($the_['function']) )
-				$args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
-
-	} while ( next($wp_filter[$tag]) !== false );
-
-	array_pop( $wp_current_filter );
-
-	return $args[0];
+	return _wp_call_hook( true, $tag, $args );
 }
 
 /**
@@ -245,21 +179,23 @@
  * @param callback $function_to_remove The name of the function which should be removed.
  * @param int $priority optional. The priority of the function (default: 10).
  * @param int $accepted_args optional. The number of arguments the function accpets (default: 1).
- * @return boolean Whether the function existed before it was removed.
+ * @return boolean True if there was a function to remove, False if not.
  */
 function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
-	$function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority);
+	global $wp_filter, $merged_filters;
 
-	$r = isset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
+	$unique_id = _wp_filter_build_unique_id($tag, $function_to_remove, $priority);
 
-	if ( true === $r) {
-		unset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
-		if ( empty($GLOBALS['wp_filter'][$tag][$priority]) )
-			unset($GLOBALS['wp_filter'][$tag][$priority]);
-		unset($GLOBALS['merged_filters'][$tag]);
-	}
+	if ( false === isset( $wp_filter[$tag][$priority][$unique_id] ) )
+		return false;
 
-	return $r;
+	unset( $merged_filters[$tag] );
+	unset( $wp_filter[$tag][$priority][$unique_id] );
+
+	if ( empty( $wp_filter[$tag][$priority] ) )
+		unset( $wp_filter[$tag][$priority] );
+
+	return true;
 }
 
 /**
@@ -268,21 +204,22 @@
  * @since 2.7
  *
  * @param string $tag The filter to remove hooks from.
- * @param int $priority The priority number to remove.
- * @return bool True when finished.
+ * @param int $priority (optional) The priority to remove.
+ * @return bool True
  */
 function remove_all_filters($tag, $priority = false) {
 	global $wp_filter, $merged_filters;
 
-	if( isset($wp_filter[$tag]) ) {
-		if( false !== $priority && isset($wp_filter[$tag][$priority]) )
-			unset($wp_filter[$tag][$priority]);
-		else
-			unset($wp_filter[$tag]);
+	if ( !isset( $wp_filter[$tag] ) )
+		return true;
+
+	if ( false === $priority ) {
+		unset( $wp_filter[$tag] );
+	} else {
+		unset( $wp_filter[$tag][$priority] );
 	}
 
-	if( isset($merged_filters[$tag]) )
-		unset($merged_filters[$tag]);
+	unset( $merged_filters[$tag] );
 
 	return true;
 }
@@ -350,53 +287,9 @@
  * @return null Will return null if $tag does not exist in $wp_filter array
  */
 function do_action($tag, $arg = '') {
-	global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
-
-	if ( ! isset($wp_actions) )
-		$wp_actions = array();
-
-	if ( ! isset($wp_actions[$tag]) )
-		$wp_actions[$tag] = 1;
-	else
-		++$wp_actions[$tag];
-
-	$wp_current_filter[] = $tag;
-
-	// Do 'all' actions first
-	if ( isset($wp_filter['all']) ) {
-		$all_args = func_get_args();
-		_wp_call_all_hook($all_args);
-	}
-
-	if ( !isset($wp_filter[$tag]) ) {
-		array_pop($wp_current_filter);
-		return;
-	}
-
-	$args = array();
-	if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
-		$args[] =& $arg[0];
-	else
-		$args[] = $arg;
-	for ( $a = 2; $a < func_num_args(); $a++ )
-		$args[] = func_get_arg($a);
-
-	// Sort
-	if ( !isset( $merged_filters[ $tag ] ) ) {
-		ksort($wp_filter[$tag]);
-		$merged_filters[ $tag ] = true;
-	}
-
-	reset( $wp_filter[ $tag ] );
-
-	do {
-		foreach ( (array) current($wp_filter[$tag]) as $the_ )
-			if ( !is_null($the_['function']) )
-				call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
-
-	} while ( next($wp_filter[$tag]) !== false );
-
-	array_pop($wp_current_filter);
+	$args = func_get_args();
+	$tag  = array_shift( $args );
+	_wp_call_hook(false, $tag, $args);
 }
 
 /**
@@ -436,45 +329,7 @@
  * @return null Will return null if $tag does not exist in $wp_filter array
  */
 function do_action_ref_array($tag, $args) {
-	global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
-
-	if ( ! isset($wp_actions) )
-		$wp_actions = array();
-
-	if ( ! isset($wp_actions[$tag]) )
-		$wp_actions[$tag] = 1;
-	else
-		++$wp_actions[$tag];
-
-	$wp_current_filter[] = $tag;
-
-	// Do 'all' actions first
-	if ( isset($wp_filter['all']) ) {
-		$all_args = func_get_args();
-		_wp_call_all_hook($all_args);
-	}
-
-	if ( !isset($wp_filter[$tag]) ) {
-		array_pop($wp_current_filter);
-		return;
-	}
-
-	// Sort
-	if ( !isset( $merged_filters[ $tag ] ) ) {
-		ksort($wp_filter[$tag]);
-		$merged_filters[ $tag ] = true;
-	}
-
-	reset( $wp_filter[ $tag ] );
-
-	do {
-		foreach( (array) current($wp_filter[$tag]) as $the_ )
-			if ( !is_null($the_['function']) )
-				call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
-
-	} while ( next($wp_filter[$tag]) !== false );
-
-	array_pop($wp_current_filter);
+	_wp_call_hook( false, $tag, $args );
 }
 
 /**
@@ -490,7 +345,7 @@
  * @return int|boolean Optionally returns the priority on that hook for the specified function.
  */
 function has_action($tag, $function_to_check = false) {
-	return has_filter($tag, $function_to_check);
+	return has_filter( $tag, $function_to_check );
 }
 
 /**
@@ -511,7 +366,7 @@
  * @return boolean Whether the function is removed.
  */
 function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
-	return remove_filter($tag, $function_to_remove, $priority, $accepted_args);
+	return remove_filter( $tag, $function_to_remove, $priority, $accepted_args );
 }
 
 /**
@@ -524,7 +379,7 @@
  * @return bool True when finished.
  */
 function remove_all_actions($tag, $priority = false) {
-	return remove_all_filters($tag, $priority);
+	return remove_all_filters( $tag, $priority );
 }
 
 //
@@ -547,14 +402,21 @@
  * @uses WP_PLUGIN_DIR
  */
 function plugin_basename($file) {
-	$file = str_replace('\\','/',$file); // sanitize for Win32 installs
-	$file = preg_replace('|/+|','/', $file); // remove any duplicate slash
-	$plugin_dir = str_replace('\\','/',WP_PLUGIN_DIR); // sanitize for Win32 installs
-	$plugin_dir = preg_replace('|/+|','/', $plugin_dir); // remove any duplicate slash
-	$mu_plugin_dir = str_replace('\\','/',WPMU_PLUGIN_DIR); // sanitize for Win32 installs
-	$mu_plugin_dir = preg_replace('|/+|','/', $mu_plugin_dir); // remove any duplicate slash
-	$file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir
-	$file = trim($file, '/');
+	$subject = array ( $file, WP_PLUGIN_DIR, WPMU_PLUGIN_DIR );
+	
+	$subject = str_replace(  '\\',   '/', $subject ); // sanitize for Win32 installs
+	$subject = preg_replace( '|/+|', '/', $subject ); // remove any duplicate slash
+	
+	$file    = array_shift( $subject );
+
+	// get relative path from plugins dir
+	$subject = array_map( 'preg_quote', $subject, array ( '#', '#' ) );
+	list ( $plugin_dir, $mu_plugin_dir ) = $subject;
+	$pattern = sprintf( '#^(%s|%s)/#', $plugin_dir, $mu_plugin_dir );
+	$file    = preg_replace( $pattern, '', $file );
+
+	$file    = trim( $file, '/' );
+
 	return $file;
 }
 
@@ -604,8 +466,8 @@
  * @param callback $function the function hooked to the 'activate_PLUGIN' action.
  */
 function register_activation_hook($file, $function) {
-	$file = plugin_basename($file);
-	add_action('activate_' . $file, $function);
+	$file = plugin_basename( $file );
+	add_action( 'activate_' . $file, $function );
 }
 
 /**
@@ -629,8 +491,8 @@
  * @param callback $function the function hooked to the 'activate_PLUGIN' action.
  */
 function register_deactivation_hook($file, $function) {
-	$file = plugin_basename($file);
-	add_action('deactivate_' . $file, $function);
+	$file = plugin_basename( $file );
+	add_action( 'deactivate_' . $file, $function );
 }
 
 /**
@@ -662,9 +524,10 @@
 	// The option should not be autoloaded, because it is not needed in most
 	// cases. Emphasis should be put on using the 'uninstall.php' way of
 	// uninstalling the plugin.
-	$uninstallable_plugins = (array) get_option('uninstall_plugins');
-	$uninstallable_plugins[plugin_basename($file)] = $callback;
-	update_option('uninstall_plugins', $uninstallable_plugins);
+	$file                         = plugin_basename($file);
+	$uninstallable_plugins        = (array) get_option( 'uninstall_plugins' );
+	$uninstallable_plugins[$file] = $callback;
+	update_option( 'uninstall_plugins', $uninstallable_plugins );
 }
 
 /**
@@ -688,16 +551,59 @@
  * @param array $args The collected parameters from the hook that was called.
  * @param string $hook Optional. The hook name that was used to call the 'all' hook.
  */
-function _wp_call_all_hook($args) {
+function _wp_call_all_hook( $args ) {
 	global $wp_filter;
 
-	reset( $wp_filter['all'] );
-	do {
-		foreach( (array) current($wp_filter['all']) as $the_ )
-			if ( !is_null($the_['function']) )
-				call_user_func_array($the_['function'], $args);
+	foreach( $wp_filter['all'] as $priority )
+		foreach( $priority as $the_ )
+			null !== $the_['function']
+			&& call_user_func_array( $the_['function'], $args );
+}
 
-	} while ( next($wp_filter['all']) !== false );
+/**
+ * Calls a hook
+ * 
+ * @since 3.1
+ * @access private
+ * @param bool   $filter True: apply_filter, False: do_action 
+ * @param string $tag The name of the filter hook.
+ * @param array  $args The arguments supplied to the functions hooked on <tt>$tag</tt>
+ * @return mixed first element of $args, filtered if applicable
+ */
+function _wp_call_hook($filter, $tag, $args) {
+	global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
+
+	// Count actions (not filters)
+	$filter || isset( $wp_actions[$tag] ) && $wp_actions[$tag]++ || $wp_actions[$tag] = 1;
+
+	// Add hook to stack
+	$wp_current_filter[] = $tag; 
+
+	// Do 'all' actions
+	isset( $wp_filter['all'] ) && _wp_call_all_hook( array_merge( array($tag), $args ) );
+
+	if ( isset( $wp_filter[$tag] ) ) {
+		// Sort
+		isset( $merged_filters[$tag] ) || $merged_filters[$tag] = ksort( $wp_filter[$tag] );
+
+		for ( $prio = reset( $wp_filter[$tag] ); false !== $prio ; $prio = next( $wp_filter[$tag] ) ) {
+			foreach( $prio as $the_ ) {
+				if ( null === $the_['function'] )
+					continue; 
+
+				$callback  = $the_['function'];
+				$parameter = array_slice( $args, 0, $the_['accepted_args'] );
+
+				$filter
+				? $args[0] = call_user_func_array( $callback, $parameter) 
+				: call_user_func_array( $callback, $parameter);
+			}
+		}
+	}
+
+	// Remove hook from stack
+	array_pop( $wp_current_filter ); 
+	return isset( $args[0] ) ? $args[0] : null;
 }
 
 /**
@@ -734,26 +640,26 @@
 	global $wp_filter;
 	static $filter_id_count = 0;
 
-	if ( is_string($function) )
+	if ( is_string( $function ) )
 		return $function;
 
-	if ( is_object($function) ) {
+	if ( is_object( $function ) ) {
 		// Closures are currently implemented as objects
 		$function = array( $function, '' );
 	} else {
 		$function = (array) $function;
 	}
 
-	if (is_object($function[0]) ) {
-		// Object Class Calling
-		if ( function_exists('spl_object_hash') ) {
-			return spl_object_hash($function[0]) . $function[1];
+	if ( is_object( $function[0] ) ) {
+		// Object Instance Calling
+		if ( function_exists( 'spl_object_hash' ) ) {
+			return spl_object_hash( $function[0] ) . $function[1];
 		} else {
-			$obj_idx = get_class($function[0]).$function[1];
-			if ( !isset($function[0]->wp_filter_id) ) {
+			$obj_idx = get_class( $function[0] ) . $function[1];
+			if ( !isset( $function[0]->wp_filter_id ) ) {
 				if ( false === $priority )
 					return false;
-				$obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count;
+				$obj_idx .= isset( $wp_filter[$tag][$priority] ) ? count( (array) $wp_filter[$tag][$priority] ) : $filter_id_count;
 				$function[0]->wp_filter_id = $filter_id_count;
 				++$filter_id_count;
 			} else {
@@ -762,8 +668,8 @@
 
 			return $obj_idx;
 		}
-	} else if ( is_string($function[0]) ) {
-		// Static Calling
+	} else if ( is_string( $function[0] ) ) {
+		// Object Static Calling
 		return $function[0].$function[1];
 	}
 }
