Index: sites/default/default.settings.php
===================================================================
RCS file: /cvs/drupal/drupal/sites/default/default.settings.php,v
retrieving revision 1.18
diff -u -p -r1.18 default.settings.php
--- sites/default/default.settings.php	23 Dec 2008 19:59:17 -0000	1.18
+++ sites/default/default.settings.php	31 Jan 2009 19:29:56 -0000
@@ -46,7 +46,7 @@
 /**
  * Database settings:
  *
- * The $databases array specifies the database connection or 
+ * The $databases array specifies the database connection or
  * connections that Drupal may use.  Drupal is able to connect
  * to multiple databases, including multiple types of databases,
  * during the same request.
@@ -63,7 +63,7 @@
  *   'port' => 3306,
  * );
  *
- * The "driver" property indicates what Drupal database driver the 
+ * The "driver" property indicates what Drupal database driver the
  * connection should use.  This is usually the same as the name of the
  * database type, such as mysql or sqlite, but not always.  The other
  * properties will vary depending on the driver.  For SQLite, you must
@@ -80,7 +80,7 @@
  * A target database allows Drupal to try to send certain queries to a
  * different database if it can but fall back to the default connection if not.
  * That is useful for master/slave replication, as Drupal may try to connect
- * to a slave server when appropriate and if one is not available will simply 
+ * to a slave server when appropriate and if one is not available will simply
  * fall back to the single master server.
  *
  * The general format for the $databases array is as follows:
@@ -232,7 +232,7 @@ ini_set('session.cookie_lifetime', 20000
  *
  * Remove the leading hash signs to enable.
  */
-# $conf = array(
+$conf = array(
 #   'site_name' => 'My Drupal site',
 #   'theme_default' => 'minnelli',
 #   'anonymous' => 'Visitor',
@@ -273,7 +273,19 @@ ini_set('session.cookie_lifetime', 20000
  * your web server spoofing the X-Forwarded-For headers.
  */
 #   'reverse_proxy_addresses' => array('a.b.c.d', ...), // Leave the comma here.
-# );
+/**
+ * The default pluggable system configuration.
+ */
+  'handlers' => array(
+    'cache' => array(
+      'default' => array(
+        'handler' => 'drupalCache',
+        'file' => 'includes/cache.inc',
+        'cache' => TRUE,
+      ),
+    ),
+  ),
+);
 
 /**
  * String overrides:
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.268
diff -u -p -r1.268 bootstrap.inc
--- includes/bootstrap.inc	25 Jan 2009 12:19:31 -0000	1.268
+++ includes/bootstrap.inc	31 Jan 2009 19:29:57 -0000
@@ -1130,9 +1130,6 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE:
-      // Allow specifying special cache handlers in settings.php, like
-      // using memcached or files for storing cache information.
-      require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc');
       // If the page_cache_fastpath is set to TRUE in settings.php and
       // page_cache_fastpath (implemented in the special implementation of
       // cache.inc) printed the page and indicated this with a returned TRUE
@@ -1615,3 +1612,154 @@ function registry_rebuild() {
 /**
  * @} End of "ingroup registry".
  */
+
+/**
+ * Set the handler to user for a slot and target.
+ *
+ * @param $slot
+ *   The internal ID of the slot for which we want to set a handler.
+ * @param $handler
+ *   The internal ID of the handler to attach to the slot and target.
+ * @param $target
+ *   The target for which we want set the handler.
+ */
+function handler_set($slot, $handler, $target = 'default') {
+  static $slot_into = array();
+  static $handler_info = array();
+
+  $handlers = variable_get('handlers', array());
+
+  if (empty($slot_info) || empty($handler_info)) {
+    $slot_info = module_invoke_all('slot_info');
+
+    foreach ($slots as $slot => $info) {
+      $slots[$slot] += array(
+        'cache' => TRUE,
+        'file' => '',
+      );
+    }
+
+    // Let other modules alter the slots.
+    drupal_alter('slot_info', $slot_info);
+
+    $handler_info = module_invoke_all('handler_info');
+
+    // Let other modules alter the handlers.
+    drupal_alter('handler_info', $handler_info);
+  }
+
+  $handlers[$slot][$target][$handler] = array(
+    'handler' => $handler_info[$slot][$handler]['class'],
+    'interface' => $slot_info[$slot]['interface'],
+    'cache' => $slot_info[$slot]['cache'],
+    'file' => isset($handler_info[$slot][$handler]['file']) ? $handler_info[$slot][$handler]['class'] : '',
+  );
+
+  variable_set('handlers', $handlers);
+}
+
+/**
+ * Get the handler configuration for a slot and target.
+ *
+ * @param $slot
+ *   The internal ID of the slot for which we want to set a handler.
+ * @param $target
+ *   The target for which we want set the handler.
+ * @return
+ *   Array containing configuration for a handler.
+ *   FALSE if now handler set or no default handler for a slot.
+ */
+function handler_get($slot, $target = 'default') {
+  static $slot_info = array();
+  static $handler_info = array();
+
+  $handlers = variable_get('handlers', array());
+
+  if (isset($handlers[$slot][$target])) {
+    return $handlers[$slot][$target];
+  }
+  else {
+    if (empty($slot_info)) {
+      $slot_info = module_invoke_all('slot_info');
+      foreach ($slots as $slot => $info) {
+        $slots[$slot] += array(
+          'cache' => TRUE,
+          'file' => '',
+        );
+      }
+
+      // Let other modules alter the slots.
+      drupal_alter('slot_info', $slot_info);
+
+      $handler_info = module_invoke_all('handler_info');
+
+      // Let other modules alter the handlers.
+      drupal_alter('handler_info', $handler_info);
+    }
+    if (!empty($slot_info[$slot]['default_handler'])) {
+      return array(
+        'handler' => $slot_info[$slot]['default_handler'],
+        'interface' => $slot_info[$slot]['interface'],
+        'cache' => $slot_info[$slot]['cache'],
+        'file' => $handler_info[$slot_info[$slot]['default_handler']]['file'],
+      );
+    }
+    else {
+      return FALSE;
+    }
+  }
+}
+
+/**
+ * Get the handler object for a slot and target.
+ *
+ * @param $slot
+ *   The internal ID of the slot for which we want to set a handler.
+ * @param $target
+ *   The target for which we want set the handler.
+ * @return
+ *   A handler object.
+ */
+function handler($slot, $target = 'default') {
+  $instances = array();
+
+  $handler_info = handler_get($slot, $target);
+
+  if (isset($instances[$slot][$target])) return $instances[$slot][$target];
+
+  if (!empty($handler_info['file'])) {
+    require_once DRUPAL_ROOT . '/' . $handler_info['file'];
+  }
+
+  $handler_name = $handler_info['handler'];
+  $handler = new $handler_name();
+
+  if ($handler_info['cache']) {
+    $instances[$slot][$target] = $handler;
+  }
+
+  return $handler;
+}
+
+/**
+ * Wrapper function for cache handler.
+ *
+ * @code
+ *   $data = cache()->get('variables', 'cache'); //Retrieve something from cache
+ *
+ */
+function cache($target = 'default') {
+  return handler('cache', $target);
+}
+
+function cache_get($cid, $table = 'cache', $target = 'default') {
+  return handler('cache', $target)->get($cid, $table = 'cache');
+}
+
+function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL, $target = 'default') {
+  return handler('cache', $target)->set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL);
+}
+
+function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE, $target = 'default') {
+  return handler('cache', $target)->clear_all($cid = NULL, $table = NULL, $wildcard = FALSE);
+}
\ No newline at end of file
Index: includes/cache.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/cache.inc,v
retrieving revision 1.27
diff -u -p -r1.27 cache.inc
--- includes/cache.inc	12 Oct 2008 04:30:05 -0000	1.27
+++ includes/cache.inc	31 Jan 2009 19:29:58 -0000
@@ -1,206 +1,208 @@
 <?php
 // $Id: cache.inc,v 1.27 2008/10/12 04:30:05 webchick Exp $
 
-/**
- * Return data from the persistent cache. Data may be stored as either plain
- * text or as serialized data. cache_get will automatically return
- * unserialized objects and arrays.
- *
- * @param $cid
- *   The cache ID of the data to retrieve.
- * @param $table
- *   The table $table to store the data in. Valid core values are
- *   'cache_filter', 'cache_menu', 'cache_page', or 'cache' for
- *   the default cache.
- * @return The cache or FALSE on failure.
- */
-function cache_get($cid, $table = 'cache') {
-  global $user;
-
-  // Garbage collection necessary when enforcing a minimum cache lifetime
-  $cache_flush = variable_get('cache_flush', 0);
-  if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
-    // Reset the variable immediately to prevent a meltdown in heavy load situations.
-    variable_set('cache_flush', 0);
-    // Time to flush old cache data
-    db_delete($table)
-      ->condition('expire', CACHE_PERMANENT, '<>')
-      ->condition('expire', $cache_flush, '<=')
-      ->execute();
-  }
-
-  $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
-  if (isset($cache->data)) {
-    // If the data is permanent or we're not enforcing a minimum cache lifetime
-    // always return the cached data.
-    if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) {
-      if ($cache->serialized) {
-        $cache->data = unserialize($cache->data);
-      }
+class drupalCache {
+  /**
+   * Return data from the persistent cache. Data may be stored as either plain
+   * text or as serialized data. cache_get will automatically return
+   * unserialized objects and arrays.
+   *
+   * @param $cid
+   *   The cache ID of the data to retrieve.
+   * @param $table
+   *   The table $table to store the data in. Valid core values are
+   *   'cache_filter', 'cache_menu', 'cache_page', or 'cache' for
+   *   the default cache.
+   * @return The cache or FALSE on failure.
+   */
+  function get($cid, $table = 'cache') {
+    global $user;
+
+    // Garbage collection necessary when enforcing a minimum cache lifetime
+    $cache_flush = variable_get('cache_flush', 0);
+    if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= REQUEST_TIME)) {
+      // Reset the variable immediately to prevent a meltdown in heavy load situations.
+      variable_set('cache_flush', 0);
+      // Time to flush old cache data
+      db_delete($table)
+        ->condition('expire', CACHE_PERMANENT, '<>')
+        ->condition('expire', $cache_flush, '<=')
+        ->execute();
     }
-    // If enforcing a minimum cache lifetime, validate that the data is
-    // currently valid for this user before we return it by making sure the
-    // cache entry was created before the timestamp in the current session's
-    // cache timer. The cache variable is loaded into the $user object by
-    // _sess_read() in session.inc.
-    else {
-      if ($user->cache > $cache->created) {
-        // This cache data is too old and thus not valid for us, ignore it.
-        return FALSE;
-      }
-      else {
+
+    $cache = db_query("SELECT data, created, headers, expire, serialized FROM {" . $table . "} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
+    if (isset($cache->data)) {
+      // If the data is permanent or we're not enforcing a minimum cache lifetime
+      // always return the cached data.
+      if ($cache->expire == CACHE_PERMANENT || !variable_get('cache_lifetime', 0)) {
         if ($cache->serialized) {
           $cache->data = unserialize($cache->data);
         }
       }
+      // If enforcing a minimum cache lifetime, validate that the data is
+      // currently valid for this user before we return it by making sure the
+      // cache entry was created before the timestamp in the current session's
+      // cache timer. The cache variable is loaded into the $user object by
+      // _sess_read() in session.inc.
+      else {
+        if ($user->cache > $cache->created) {
+          // This cache data is too old and thus not valid for us, ignore it.
+          return FALSE;
+        }
+        else {
+          if ($cache->serialized) {
+            $cache->data = unserialize($cache->data);
+          }
+        }
+      }
+      return $cache;
     }
-    return $cache;
+    return FALSE;
   }
-  return FALSE;
-}
 
-/**
- * Store data in the persistent cache.
- *
- * The persistent cache is split up into four database
- * tables. Contributed modules can add additional tables.
- *
- * 'cache_page': This table stores generated pages for anonymous
- * users. This is the only table affected by the page cache setting on
- * the administrator panel.
- *
- * 'cache_menu': Stores the cachable part of the users' menus.
- *
- * 'cache_filter': Stores filtered pieces of content. This table is
- * periodically cleared of stale entries by cron.
- *
- * 'cache': Generic cache storage table.
- *
- * The reasons for having several tables are as follows:
- *
- * - smaller tables allow for faster selects and inserts
- * - we try to put fast changing cache items and rather static
- *   ones into different tables. The effect is that only the fast
- *   changing tables will need a lot of writes to disk. The more
- *   static tables will also be better cachable with MySQL's query cache
- *
- * @param $cid
- *   The cache ID of the data to store.
- * @param $data
- *   The data to store in the cache. Complex data types will be automatically
- *   serialized before insertion.
- *   Strings will be stored as plain text and not serialized.
- * @param $table
- *   The table $table to store the data in. Valid core values are
- *   'cache_filter', 'cache_menu', 'cache_page', or 'cache'.
- * @param $expire
- *   One of the following values:
- *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
- *     explicitly told to using cache_clear_all() with a cache ID.
- *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
- *     general cache wipe.
- *   - A Unix timestamp: Indicates that the item should be kept at least until
- *     the given time, after which it behaves like CACHE_TEMPORARY.
- * @param $headers
- *   A string containing HTTP header information for cached pages.
- */
-function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL) {
-  $fields = array(
-    'serialized' => 0,
-    'created' => REQUEST_TIME,
-    'expire' => $expire,
-    'headers' => $headers,
-  );
-  if (!is_string($data)) {
-    $fields['data'] = serialize($data);
-    $fields['serialized'] = 1;
-  }
-  else {
-    $fields['data'] = $data;
-    $fields['serialized'] = 0;
-  }
-
-  db_merge($table)
-    ->key(array('cid' => $cid))
-    ->fields($fields)
-    ->execute();
-}
+  /**
+   * Store data in the persistent cache.
+   *
+   * The persistent cache is split up into four database
+   * tables. Contributed modules can add additional tables.
+   *
+   * 'cache_page': This table stores generated pages for anonymous
+   * users. This is the only table affected by the page cache setting on
+   * the administrator panel.
+   *
+   * 'cache_menu': Stores the cachable part of the users' menus.
+   *
+   * 'cache_filter': Stores filtered pieces of content. This table is
+   * periodically cleared of stale entries by cron.
+   *
+   * 'cache': Generic cache storage table.
+   *
+   * The reasons for having several tables are as follows:
+   *
+   * - smaller tables allow for faster selects and inserts
+   * - we try to put fast changing cache items and rather static
+   *   ones into different tables. The effect is that only the fast
+   *   changing tables will need a lot of writes to disk. The more
+   *   static tables will also be better cachable with MySQL's query cache
+   *
+   * @param $cid
+   *   The cache ID of the data to store.
+   * @param $data
+   *   The data to store in the cache. Complex data types will be automatically
+   *   serialized before insertion.
+   *   Strings will be stored as plain text and not serialized.
+   * @param $table
+   *   The table $table to store the data in. Valid core values are
+   *   'cache_filter', 'cache_menu', 'cache_page', or 'cache'.
+   * @param $expire
+   *   One of the following values:
+   *   - CACHE_PERMANENT: Indicates that the item should never be removed unless
+   *     explicitly told to using cache_clear_all() with a cache ID.
+   *   - CACHE_TEMPORARY: Indicates that the item should be removed at the next
+   *     general cache wipe.
+   *   - A Unix timestamp: Indicates that the item should be kept at least until
+   *     the given time, after which it behaves like CACHE_TEMPORARY.
+   * @param $headers
+   *   A string containing HTTP header information for cached pages.
+   */
+  function set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL) {
+    $fields = array(
+      'serialized' => 0,
+      'created' => REQUEST_TIME,
+      'expire' => $expire,
+      'headers' => $headers,
+    );
+    if (!is_string($data)) {
+      $fields['data'] = serialize($data);
+      $fields['serialized'] = 1;
+    }
+    else {
+      $fields['data'] = $data;
+      $fields['serialized'] = 0;
+    }
 
-/**
- *
- * Expire data from the cache. If called without arguments, expirable
- * entries will be cleared from the cache_page and cache_block tables.
- *
- * @param $cid
- *   If set, the cache ID to delete. Otherwise, all cache entries that can
- *   expire are deleted.
- *
- * @param $table
- *   If set, the table $table to delete from. Mandatory
- *   argument if $cid is set.
- *
- * @param $wildcard
- *   If set to TRUE, the $cid is treated as a substring
- *   to match rather than a complete ID. The match is a right hand
- *   match. If '*' is given as $cid, the table $table will be emptied.
- */
-function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) {
-  global $user;
-
-  if (!isset($cid) && !isset($table)) {
-    // Clear the block cache first, so stale data will
-    // not end up in the page cache.
-    cache_clear_all(NULL, 'cache_block');
-    cache_clear_all(NULL, 'cache_page');
-    return;
+    db_merge($table)
+      ->key(array('cid' => $cid))
+      ->fields($fields)
+      ->execute();
   }
 
-  if (empty($cid)) {
-    if (variable_get('cache_lifetime', 0)) {
-      // We store the time in the current user's $user->cache variable which
-      // will be saved into the sessions table by _sess_write(). We then
-      // simulate that the cache was flushed for this user by not returning
-      // cached data that was cached before the timestamp.
-      $user->cache = REQUEST_TIME;
-
-      $cache_flush = variable_get('cache_flush', 0);
-      if ($cache_flush == 0) {
-        // This is the first request to clear the cache, start a timer.
-        variable_set('cache_flush', REQUEST_TIME);
-      }
-      elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
-        // Clear the cache for everyone, cache_flush_delay seconds have
-        // passed since the first request to clear the cache.
+  /**
+   *
+   * Expire data from the cache. If called without arguments, expirable
+   * entries will be cleared from the cache_page and cache_block tables.
+   *
+   * @param $cid
+   *   If set, the cache ID to delete. Otherwise, all cache entries that can
+   *   expire are deleted.
+   *
+   * @param $table
+   *   If set, the table $table to delete from. Mandatory
+   *   argument if $cid is set.
+   *
+   * @param $wildcard
+   *   If set to TRUE, the $cid is treated as a substring
+   *   to match rather than a complete ID. The match is a right hand
+   *   match. If '*' is given as $cid, the table $table will be emptied.
+   */
+  function clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) {
+    global $user;
+
+    if (!isset($cid) && !isset($table)) {
+      // Clear the block cache first, so stale data will
+      // not end up in the page cache.
+      cache_clear_all(NULL, 'cache_block');
+      cache_clear_all(NULL, 'cache_page');
+      return;
+    }
+
+    if (empty($cid)) {
+      if (variable_get('cache_lifetime', 0)) {
+        // We store the time in the current user's $user->cache variable which
+        // will be saved into the sessions table by _sess_write(). We then
+        // simulate that the cache was flushed for this user by not returning
+        // cached data that was cached before the timestamp.
+        $user->cache = REQUEST_TIME;
+
+        $cache_flush = variable_get('cache_flush', 0);
+        if ($cache_flush == 0) {
+          // This is the first request to clear the cache, start a timer.
+          variable_set('cache_flush', REQUEST_TIME);
+        }
+        elseif (REQUEST_TIME > ($cache_flush + variable_get('cache_lifetime', 0))) {
+          // Clear the cache for everyone, cache_flush_delay seconds have
+          // passed since the first request to clear the cache.
+          db_delete($table)
+            ->condition('expire', CACHE_PERMANENT, '<>')
+            ->condition('expire', REQUEST_TIME, '<')
+            ->execute();
+          variable_set('cache_flush', 0);
+        }
+      }
+      else {
+        // No minimum cache lifetime, flush all temporary cache entries now.
         db_delete($table)
           ->condition('expire', CACHE_PERMANENT, '<>')
           ->condition('expire', REQUEST_TIME, '<')
           ->execute();
-        variable_set('cache_flush', 0);
       }
     }
     else {
-      // No minimum cache lifetime, flush all temporary cache entries now.
-      db_delete($table)
-        ->condition('expire', CACHE_PERMANENT, '<>')
-        ->condition('expire', REQUEST_TIME, '<')
-        ->execute();
-    }
-  }
-  else {
-    if ($wildcard) {
-      if ($cid == '*') {
-        db_delete($table)->execute();
+      if ($wildcard) {
+        if ($cid == '*') {
+          db_delete($table)->execute();
+        }
+        else {
+          db_delete($table)
+            ->condition('cid', $cid . '%', 'LIKE')
+            ->execute();
+        }
       }
       else {
         db_delete($table)
-          ->condition('cid', $cid . '%', 'LIKE')
+          ->condition('cid', $cid)
           ->execute();
       }
     }
-    else {
-      db_delete($table)
-        ->condition('cid', $cid)
-        ->execute();
-    }
   }
 }
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.16
diff -u -p -r1.16 system.api.php
--- modules/system/system.api.php	29 Jan 2009 14:37:40 -0000	1.16
+++ modules/system/system.api.php	31 Jan 2009 19:29:59 -0000
@@ -212,7 +212,7 @@ function hook_js_alter(&$javascript) {
  *   $page['content']['nodes'][$nid]['#node']
  *   // The results pager.
  *   $page['content']['pager']
- * @code 
+ * @code
  *
  * Blocks may be referenced by their module/delta pair within a region:
  * @code
@@ -1636,5 +1636,114 @@ function hook_disable() {
 }
 
 /**
+ * Define one or more slots for the handlers system.
+ *
+ * This hook should return a nested array of slot definitions.  Each key
+ * in the array is the machine-readable slot name, and its value is an array
+ * of values that define the slot.
+ *
+ * description
+ *   A human-readable description of what the slot is for.
+ * interface
+ *   The PHP interface that defines this slot.  The interface must extend
+ *   HandlerInterface, but otherwise may define whatever methods it wants.
+ *   It may also be placed in any file, depending on what would provide the
+ *   most performance for autoloading.
+ * default_handler (optional)
+ *   The machine-readable name of the default handler for this slot, as defined
+ *   in hook_handler_info().  All slots must have at least one handler
+ *   available.  If not specified, "default" is used.
+ * cache (optional)
+ *   Whether a handler object can be cached for this slot. Defaults to TRUE.
+ *
+ * @return
+ *   A slot definition array.
+ */
+function hook_slot_info() {
+  return array(
+    'fancystring' => array(
+      'description' => 'Do fancy stuff to strings',
+      'interface' => 'FancystringInterface',
+      'default_handler' => 'default',
+    ),
+    'other' => array(
+      'description' => 'Dummy',
+      'targets' => array(),
+      'interface' => 'OtherInterface',
+      'cache' => FALSE,
+    ),
+  );
+}
+
+/**
+ * Alter the slot definitions of another module.
+ *
+ * @param $info
+ *   The complete slot definition array from hook_slot_info().
+ */
+function hook_slot_info_alter(&$info) {
+// Set a custom default handler.
+  $info['fancystring']['default_handler'] = 'stringManglerDefault';
+}
+
+/**
+ * Define one or more handlers in the system.
+ *
+ * This hook should return a doubly-nested array of handler definitions.  The
+ * first key is an existing slot.  Its value is an associative array of handler
+ * machine-readable names and handler definitions.
+ *
+ * Each handler definition is an associative array of values that define the
+ * handler.
+ *
+ * description
+ *   A human-readable description of the handler.
+ * class
+ *   The PHP class that defines this handler.  The class must implement the
+ *   interface defined for this slot, but otherwise may be defined in any way
+ *   desired, including implementing the interface directly or indirectly by
+ *   subclassing another class that implements that interface. It may also be
+ *   placed in any file, depending on what would provide the most performance
+ *   for autoloading.
+ * file (optional)
+ *   A file to load which includes the class being loaded. Note that this should
+ *   only be used in cases where the registry is not available to automatincally load
+ *   the class.
+ *
+ * @return
+ *   A handler definition array.
+ */
+function hook_handler_info() {
+  return array(
+    'fancystring' => array(
+       'default' => array(
+         // Translate on load, not define, like hook_menu().
+         'class' => 'FancystringDefault',
+         'description' => "This handler doesn't do anything to the string.  It passes through unaltered.",
+       ),
+       'rot13' => array(
+         'class' => 'FancystringRot13',
+         'description' => 'This handler ROT13 encrypts a string.',
+       ),
+       'custom_translate' => array(
+         'class' => 'FancystringCustom',
+         'description' => 'This handler uses a user-specified mapping array.',
+       ),
+     ),
+  );
+}
+
+/**
+ * Alter the handler definitions of another module.
+ *
+ * @param $info
+ *   The complete handler definition array from hook_handler_info().
+ */
+function hook_handler_info_alter(&$info) {
+  // change the class used by the rot13 handler.
+  $info['fancystring']['rot13']['class'] = 'FancystringRot13Alternate';
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.663
diff -u -p -r1.663 system.module
--- modules/system/system.module	31 Jan 2009 15:55:05 -0000	1.663
+++ modules/system/system.module	31 Jan 2009 19:30:00 -0000
@@ -2273,3 +2273,57 @@ function theme_meta_generator_header($ve
 function system_image_toolkits() {
   return array('gd');
 }
+
+/**
+ * Implementation of hook_slot_info().
+ */
+function system_slot_info() {
+  return array(
+    'cache' => array(
+      'description' => 'Drupals caching system.',
+      'interface' => 'cacheInterface',
+      'default_handler' => 'drupalCache',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_handler_info().
+ */
+function system_handler_info() {
+  return array(
+    'cache' => array(
+      'drupalCache' => array(
+        'description' => 'Drupals default database cache.',
+        'class' => 'drupalCache',
+        'file' => 'includes/cache.inc',
+      ),
+    ),
+  );
+}
+
+/**
+ * Interface for pluggable caching system.
+ */
+interface cacheInterface {
+  /**
+   * Return data from the persistent cache.
+   *
+   * @todo Add param and return details.
+   */
+  function get($cid, $table = 'cache');
+
+  /**
+   * Store data in the persistent cache.
+   *
+   * @todo Add param and return details.
+   */
+  function set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL);
+
+  /**
+   * Expire data from the cache.
+   *
+   * @todo Add param and return details.
+   */
+  function clear_all($cid = NULL, $table = NULL, $wildcard = FALSE);
+}
\ No newline at end of file
