Index: token.module
===================================================================
--- token.module	(.../trunk)	(revision 2032)
+++ token.module	(.../tags/6.x-1.x-dev-patched1)	(revision 2032)
@@ -232,11 +232,17 @@
  *   of tokens in a single execution cycle. Flushing it will
  *   keep them from burning through memory.
  *   The default is FALSE.
+ * @param options
+ *   Options are delegated to the hooks implementing "token_values"
+ * @param pattern
+ *   Token pattern limit the construction of tokens to those which are really needed,
+ *   e. g. the pattern "items/[nid]" only calls the node_token_values() function. This leads
+ *   to significant performance improvements when using a large number of modules (and tokens).
  * @return
  *   A keyed array containing the substitution tokens and the substitution
  *   values for the passed-in type and object.
  */
-function token_get_values($type = 'global', $object = NULL, $flush = FALSE, $options = array()) {
+function token_get_values($type = 'global', $object = NULL, $flush = FALSE, $options = array(), $pattern = NULL) {
   static $tokens;
   static $running;
 
@@ -274,7 +280,18 @@
     $tmp_tokens = $tokens[$type][$id];
   }
   else {
-    $tmp_tokens = module_invoke_all('token_values', $type, $object, $options);
+  	//Providing token patterns limit the token construction to the tokens which occur inside
+  	//the pattern. Therefore the tokens have to be retrieved from the pattern first. Then only
+  	//the needed hook_token_values are invoked instead of iterating over all.
+  	if ($pattern) {
+  	  $toks = token_extract_tokens($pattern); //get the needed tokens
+  	  $tmp_tokens = _token_get_values($type, $object, $toks, $options); //call the necessary hooks
+  	  if (!$tmp_tokens) //switch back to standard mode if an error occured
+  	    $tmp_tokens = module_invoke_all('token_values', $type, $object, $options);
+  	}
+  	else {
+      $tmp_tokens = module_invoke_all('token_values', $type, $object, $options);
+  	}
     $tokens[$type][$id] = $tmp_tokens;
   }
 
@@ -296,6 +313,87 @@
 }
 
 /**
+ * List all tokens first and call only those token_values hooks
+ * which provide this token. It assumes that the hook token_list() is 
+ * implemented in the same module as the hook token_values() which should
+ * be the usual convention.
+ * @param type
+ *   A flag indicating the class of substitution tokens to use. If an
+ *   object is passed in the second param, 'type' should contain the
+ *   object's type. For example, 'node', 'comment', or 'user'. If no
+ *   type is specified, only 'global' site-wide substitution tokens are
+ *   built.
+ * @param object
+ *   Optionally, the object to use for building substitution values.
+ *   A node, comment, user, etc.
+ * @param $toks
+ *   Array of tokens which should be replaced.
+ * @param options
+ *   Options are delegated to the hooks implementing "token_values"
+ * @return 
+ *   Corresponding dynamic values of the tokens in $toks array.
+ */
+function _token_get_values($type, $object, $toks, $options) {  
+  $values = array();
+  
+  token_include(); //load PHP include files
+  
+  //list all tokens first because these are cheap calls.
+  foreach (module_implements('token_list') as $module) {
+    $function = $module .'_token_list';
+    $result = $function($type);
+    if (is_array($result)) {
+      foreach ($result as $category => $tokens) {
+        foreach ($tokens as $token => $title) {  //iterate the token definitions
+          if (in_array($token, $toks)) { //build the tokens if they occur in the list
+            $func_values = $module . '_token_values';
+            //Add the token values if they provide values.
+            if (function_exists($func_values) && $ret_values = $func_values($type, $object, FALSE, $options)) {
+              $values = array_merge($values, $ret_values);
+            }
+            else { //error occurred, abort this execution 
+              return FALSE;
+            }
+          }
+        }
+      }
+    }
+  }
+  //clean up unnecessary values generated by the hook_token_values
+   foreach ($values as $key => &$value) {
+   	if (!in_array($key, $toks)) {
+   	  unset($values[$key]);
+   	}
+   }
+   return $values;
+}
+
+/**
+ * Given a token pattern string, which is usually stored as a variable,
+ * all tokens different tokens are retrieved from it. The node token
+ * pattern [type]/items/[nid]/view returns an array("type
+ * @param $pattern
+ */
+function token_extract_tokens($pattern) {
+  $tokens = array();
+  for ($start = $end = 0; strpos($pattern, ']', $end+1) > $start;) {
+    $start = strpos($pattern, '[', $end)+1;
+    if (!$start)
+      break;
+
+    $end = strpos($pattern, ']', $start);
+    if (!$end || $end < $start)
+      break;
+    
+    $len = $end - $start;
+    $token = substr($pattern, $start, $len);
+    if (!in_array($token, $tokens))
+      $tokens[] = $token;
+  }
+  return $tokens;
+}
+
+/**
  * A helper function that retrieves all currently exposed tokens,
  * and merges them recursively. This is only necessary when building
  * the token listing -- during actual value replacement, only tokens
