Index: autoload.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/autoload/Attic/autoload.install,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 autoload.install
--- autoload.install	3 Jun 2010 03:33:11 -0000	1.1.2.2
+++ autoload.install	22 Aug 2010 22:02:06 -0000
@@ -2,12 +2,96 @@
 // $Id: autoload.install,v 1.1.2.2 2010/06/03 03:33:11 crell Exp $
 
 /**
- * Implementaton of hook_enable().
+ * Implements hook_schema().
+ */
+function autoload_schema() {
+  $schema['autoload_registry'] = array(
+    'description' => "Each record is a function, class, or interface name and the file it is in.",
+    'fields' => array(
+      'name'   => array(
+        'description' => 'The name of the function, class, or interface.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'type'   => array(
+        'description' => 'Either function or class or interface.',
+        'type' => 'varchar',
+        'length' => 9,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'filename'   => array(
+        'description' => 'Name of the file.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'module' => array(
+        'description' => 'Name of the module the file belongs to.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'weight' => array(
+        'description' => "The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name.",
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('name', 'type'),
+    'indexes' => array(
+      'hook' => array('type', 'weight', 'module'),
+    ),
+  );
+
+  $schema['autoload_registry_file'] = array(
+    'description' => "Files parsed to build the registry.",
+    'fields' => array(
+      'filename'   => array(
+        'description' => 'Path to the file.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'hash'  => array(
+        'description' => "sha-256 hash of the file's contents when last parsed.",
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('filename'),
+  );
+
+  return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
+function autoload_install() {
+  drupal_install_schema('autoload');
+}
+
+/**
+ * Implements hook_enable().
  */
 function autoload_enable() {
   db_query("UPDATE {system} SET weight = -100 WHERE name = 'autoload' AND type = 'module'");
 
   spl_autoload_register('autoload_class');
+  spl_autoload_register('autoload_interface');
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function autoload_uninstall() {
+  drupal_uninstall_schema('autoload');
 }
 
 /**
@@ -18,3 +102,76 @@ function autoload_update_6001() {
 
   return array();
 }
+
+/**
+ * Convert to using the backport D7 registry.
+ */
+function autoload_update_6002() {
+    $schema['autoload_registry'] = array(
+    'description' => "Each record is a function, class, or interface name and the file it is in.",
+    'fields' => array(
+      'name'   => array(
+        'description' => 'The name of the function, class, or interface.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'type'   => array(
+        'description' => 'Either function or class or interface.',
+        'type' => 'varchar',
+        'length' => 9,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'filename'   => array(
+        'description' => 'Name of the file.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'module' => array(
+        'description' => 'Name of the module the file belongs to.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'weight' => array(
+        'description' => "The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name.",
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('name', 'type'),
+    'indexes' => array(
+      'hook' => array('type', 'weight', 'module'),
+    ),
+  );
+  $schema['autoload_registry_file'] = array(
+    'description' => "Files parsed to build the registry.",
+    'fields' => array(
+      'filename'   => array(
+        'description' => 'Path to the file.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'hash'  => array(
+        'description' => "sha-256 hash of the file's contents when last parsed.",
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('filename'),
+  );
+
+  $ret = array();
+  foreach ($schema as $table => $table_schema) {
+    db_create_table($ret, $table, $table_schema);
+  }
+
+  return $ret;
+}
Index: autoload.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/autoload/autoload.module,v
retrieving revision 1.1.2.11
diff -u -p -r1.1.2.11 autoload.module
--- autoload.module	29 Jun 2010 23:55:38 -0000	1.1.2.11
+++ autoload.module	22 Aug 2010 22:02:06 -0000
@@ -1,77 +1,194 @@
 <?php
 // $Id: autoload.module,v 1.1.2.11 2010/06/29 23:55:38 crell Exp $
+
+/**
+ * Signals that the registry lookup cache should be reset.
+ */
+define('AUTOLOAD_REGISTRY_RESET_LOOKUP_CACHE', 1);
+
 /**
- * Implementation of hook_init().
+ * Signals that the registry lookup cache should be written to storage.
  */
-function autoload_init() {
+define('AUTOLOAD_REGISTRY_WRITE_LOOKUP_CACHE', 2);
+
+/**
+ * Implements hook_boot().
+ */
+function autoload_boot() {
   spl_autoload_register('autoload_class');
+  spl_autoload_register('autoload_interface');
 }
 
 /**
- * Implementation of hook_flush_caches().
+ * Implements hook_exit().
  */
-function autoload_flush_caches() {
-  // Force a rescan of the autload hook.
-  autoload_get_lookup(TRUE);
+function autoload_exit() {
+  if (function_exists('drupal_page_footer')) {
+    _autoload_registry_check_code(AUTOLOAD_REGISTRY_WRITE_LOOKUP_CACHE);
+  }
 }
 
 /**
- * Autoload function for registered classes.
+ * Implements hook_flush_caches().
  */
-function autoload_class($class) {
-  $lookup = autoload_get_lookup();
+function autoload_flush_caches() {
+  autoload_registry_rebuild();
+}
 
-   if (!empty($lookup[$class])) {
-    // require() is safe because if the file were already included
-    // autoload wouldn't have been triggered.
-    $path = realpath($lookup[$class]);
-    if (!empty($path)) {
-      require $path;
-    }
+/**
+ * Implements hook_form_alter().
+ */
+function autoload_form_alter(&$form, $form_state, $form_id) {
+  switch ($form_id) {
+    case 'system_modules':
+      $form['#submit'][] = 'autoload_form_submit_registry_rebuild';
+      break;
   }
 }
 
 /**
- * Build and return the lookup table for classes and interfaces.
+ * Form submit handler; rebuild the autoload registry.
+ */
+function autoload_form_submit_registry_rebuild() {
+  autoload_registry_rebuild();
+}
+
+/**
+ * @ingroup registry
+ * @{
+ */
+
+/**
+ * Confirm that an interface is available.
+ *
+ * This function is rarely called directly. Instead, it is registered as an
+ * spl_autoload() handler, and PHP calls it for us when necessary.
+ *
+ * @param $interface
+ *   The name of the interface to check or load.
+ * @return
+ *   TRUE if the interface is currently available, FALSE otherwise.
+ */
+function autoload_interface($interface) {
+  return _autoload_registry_check_code('interface', $interface);
+}
+
+/**
+ * Confirm that a class is available.
+ *
+ * This function is rarely called directly. Instead, it is registered as an
+ * spl_autoload() handler, and PHP calls it for us when necessary.
+ *
+ * @param $class
+ *   The name of the class to check or load.
+ * @return
+ *   TRUE if the class is currently available, FALSE otherwise.
+ */
+function autoload_class($class) {
+  return _autoload_registry_check_code('class', $class);
+}
+
+/**
+ * Helper to check for a resource in the registry.
  *
+ * @param $type
+ *   The type of resource we are looking up, or one of the constants
+ *   REGISTRY_RESET_LOOKUP_CACHE or REGISTRY_WRITE_LOOKUP_CACHE, which
+ *   signal that we should reset or write the cache, respectively.
+ * @param $name
+ *   The name of the resource, or NULL if either of the REGISTRY_* constants
+ *   is passed in.
  * @return
- *   The lookup table for what classes are stored where.
+ *   TRUE if the resource was found, FALSE if not.
+ *   NULL if either of the REGISTRY_* constants is passed in as $type.
  */
-function autoload_get_lookup($reset = FALSE) {
-  static $lookup;
+function _autoload_registry_check_code($type, $name = NULL) {
+  static $lookup_cache, $cache_update_needed;
 
-  if (isset($lookup) && !$reset) {
-    return $lookup;
+  if (($type == 'class' && class_exists($name)) || ($type == 'interface' && interface_exists($name))) {
+    return TRUE;
   }
 
-  if (!$reset && ($cache = cache_get('autoload:')) && isset($cache->data)) {
-    $lookup = $cache->data;
+  if (!isset($lookup_cache)) {
+    $lookup_cache = array();
+    if ($cache = cache_get('autoload')) {
+      $lookup_cache = $cache->data;
+    }
   }
-  else {
-    // We need to manually call each module so that we can know which module
-    // a given item came from.
-    $classes = array();
-    foreach (module_implements('autoload_info') as $module) {
-      $class_items = call_user_func($module .'_autoload_info');
-      if (isset($class_items) && is_array($class_items)) {
-        foreach (array_keys($class_items) as $item) {
-          $class_items[$item]['module'] = $module;
-        }
-        $classes = array_merge($classes, $class_items);
-      }
+
+  // When we rebuild the registry, we need to reset this cache so
+  // we don't keep lookups for resources that changed during the rebuild.
+  if ($type == AUTOLOAD_REGISTRY_RESET_LOOKUP_CACHE) {
+    $cache_update_needed = TRUE;
+    $lookup_cache = NULL;
+    return;
+  }
+
+  // Called from drupal_page_footer, we write to permanent storage if there
+  // changes to the lookup cache for this request.
+  if ($type == AUTOLOAD_REGISTRY_WRITE_LOOKUP_CACHE) {
+    if ($cache_update_needed) {
+      cache_set('autoload', $lookup_cache);
     }
-    // Alter the lookup table as defined by modules. The keys are class and interface names.
-    drupal_alter('autoload_info', $classes);
+    return;
+  }
 
-    // Derive the full path name and store just the lookup table itself.
-    $lookup = array();
-    foreach ($classes as $class => $item) {
-      $file_path = isset($item['file path']) ? $item['file path'] : drupal_get_path('module', $item['module']);
-      $lookup[$class] = $file_path .'/'. $item['file'];
+  // $type is either 'interface' or 'class', so we only need the first letter to
+  // keep the cache key unique.
+  $cache_key = $type[0] . $name;
+  if (isset($lookup_cache[$cache_key])) {
+    if ($lookup_cache[$cache_key]) {
+      require_once './' . $lookup_cache[$cache_key];
     }
+    return (bool) $lookup_cache[$cache_key];
+  }
 
-    // Save the lookup table, then return it.
-    cache_set('autoload:', $lookup);
+  // This function may get called when the default database is not active, but
+  // there is no reason we'd ever want to not use the default database for
+  // this query.
+  $file = db_result(db_query("SELECT filename FROM {autoload_registry} WHERE name = '%s' AND type = '%s'", $name, $type));
+
+  // Flag that we've run a lookup query and need to update the cache.
+  $cache_update_needed = TRUE;
+
+  // Misses are valuable information worth caching, so cache even if
+  // $file is FALSE.
+  $lookup_cache[$cache_key] = $file;
+
+  if ($file) {
+    require_once './' . $file;
+    return TRUE;
+  }
+  else {
+    return FALSE;
   }
-  return $lookup;
 }
+
+/**
+ * Rescan all enabled modules and rebuild the registry.
+ *
+ * Rescans all code in modules or includes directories, storing the location of
+ * each interface or class in the database.
+ */
+function autoload_registry_rebuild() {
+  module_rebuild_cache();
+  autoload_registry_update();
+}
+
+/**
+ * Update the registry based on the latest files listed in the database.
+ *
+ * This function should be used when system_rebuild_module_data() does not need
+ * to be called, because it is already known that the list of files in the
+ * {system} table matches those in the file system.
+ *
+ * @see autoload_registry_rebuild()
+ */
+function autoload_registry_update() {
+  module_load_include('inc', 'autoload', 'autoload.registry');
+  _autoload_registry_update();
+}
+
+/**
+ * @} End of "ingroup registry".
+ */
Index: autoload.registry.inc
===================================================================
RCS file: autoload.registry.inc
diff -N autoload.registry.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ autoload.registry.inc	22 Aug 2010 22:02:06 -0000
@@ -0,0 +1,186 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * This file contains the code registry parser engine. This file is backported
+ * from Drupal 7 core's registry.inc file.
+ */
+
+/**
+ * @defgroup registry Code registry
+ * @{
+ * The code registry engine.
+ *
+ * Autoload maintains an internal registry of all functions or classes in the
+ * system, allowing it to lazy-load code files as needed (reducing the amount
+ * of code that must be parsed on each request).
+ */
+
+/**
+ * Does the work for autoload_registry_update().
+ */
+function _autoload_registry_update() {
+  // Get current list of modules and their files.
+  $modules = array();
+  $query = db_query("SELECT * FROM {system} WHERE type = 'module'");
+  // Get the list of files we are going to parse.
+  $files = array();
+  while ($module = db_fetch_object($query)) {
+    $modules[$module->name] = &$module;
+    $module->info = unserialize($module->info);
+    $dir = dirname($module->filename);
+
+    // Store the module directory for use in hook_registry_files_alter().
+    $module->dir = $dir;
+
+    if ($module->status && !empty($module->info['files'])) {
+      // Add files for enabled modules to the registry.
+      foreach ($module->info['files'] as $file) {
+        $files["$dir/$file"] = array('module' => $module->name, 'weight' => $module->weight);
+      }
+    }
+  }
+  foreach (file_scan_directory('includes', '/\.inc$/') as $filename => $file) {
+    $files["$filename"] = array('module' => '', 'weight' => 0);
+  }
+
+  // Add support for the old-style hook_autoload_info() data.
+  $classes = array();
+  foreach (module_implements('autoload_info') as $module) {
+    $module_classes = module_invoke($module, 'autoload_info');
+    if (isset($module_classes) && is_array($module_classes)) {
+      foreach (array_keys($module_classes) as $item) {
+        $module_classes[$item] += array(
+          'module' => $module,
+          'file path' => drupal_get_path('module', $module),
+          'weight' => isset($modules[$module]) ? $modules[$module]->weight : 0,
+        );
+      }
+      $classes = array_merge($classes, $module_classes);
+    }
+  }
+  // Alter the lookup table as defined by modules. The keys are class and interface names.
+  drupal_alter('autoload_info', $classes);
+  foreach ($classes as $item) {
+    $filename = $item['file path'] . '/' . $item['file'];
+    if (!isset($files[$filename])) {
+      $files["$filename"] = array('module' => $item['module'], 'weight' => $item['weight']);
+    }
+  }
+
+  try {
+    // Allow modules to manually modify the list of files before the registry
+    // parses them. The $modules array provides the .info file information, which
+    // includes the list of files registered to each module. Any files in the
+    // list can then be added to the list of files that the registry will parse,
+    // or modify attributes of a file.
+    drupal_alter('autoload_registry_files', $files, $modules);
+    foreach (autoload_registry_get_parsed_files() as $filename => $file) {
+      // Add the hash for those files we have already parsed.
+      if (isset($files[$filename])) {
+        $files[$filename]['hash'] = $file['hash'];
+      }
+      else {
+        // Flush the registry of resources in files that are no longer on disc
+        // or are in files that no installed modules require to be parsed.
+        db_query("DELETE FROM {autoload_registry} WHERE filename = '%s'", $filename);
+        db_query("DELETE FROM {autoload_registry_file} WHERE filename = '%s'", $filename);
+      }
+    }
+    $parsed_files = _autoload_registry_parse_files($files);
+
+    $unchanged_resources = array();
+    $lookup_cache = array();
+    if ($cache = cache_get('autoload')) {
+      $lookup_cache = $cache->data;
+    }
+    foreach ($lookup_cache as $key => $file) {
+      // If the file for this cached resource is carried over unchanged from
+      // the last registry build, then we can safely re-cache it.
+      if ($file && in_array($file, array_keys($files)) && !in_array($file, $parsed_files)) {
+        $unchanged_resources[$key] = $file;
+      }
+    }
+    module_implements('', '', TRUE);
+    _autoload_registry_check_code(AUTOLOAD_REGISTRY_RESET_LOOKUP_CACHE);
+  }
+  catch (Exception $e) {
+    throw $e;
+  }
+
+  // We have some unchanged resources, warm up the cache - no need to pay
+  // for looking them up again.
+  if (count($unchanged_resources) > 0) {
+    cache_set('autoload', $unchanged_resources);
+  }
+}
+
+/**
+ * Return the list of files in registry_file
+ */
+function autoload_registry_get_parsed_files() {
+  $files = array();
+  // We want the result as a keyed array.
+  $query = db_query("SELECT * FROM {autoload_registry_file}");
+  while ($file = db_fetch_object($query)) {
+    $files[$file->filename] = $file;
+  }
+  return $files;
+}
+
+/**
+ * Parse all files that have changed since the registry was last built, and
+ * save their function and class listings.
+ *
+ * @param $files
+ *  The list of files to check and parse.
+ */
+function _autoload_registry_parse_file($filename, $contents, $module = '', $weight = 0) {
+  if (preg_match_all('/^\s*(?:abstract)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
+    foreach ($matches[2] as $key => $name) {
+      db_query("INSERT INTO {autoload_registry} (name, type, filename, module, weight) VALUES ('%s', '%s', '%s', '%s', %d)", array(
+        $name,
+        $matches[1][$key],
+        $filename,
+        $module,
+        $weight,
+      ));
+    }
+  }
+}
+
+/**
+ * Parse a file and save its function and class listings.
+ *
+ * @param $filename
+ *  Name of the file we are going to parse.
+ * @param $contents
+ *  Contents of the file we are going to parse as a string.
+ * @param $module
+ *   (optional) Name of the module this file belongs to.
+ * @param $weight
+ *   (optional) Weight of the module.
+ */
+function _autoload_registry_parse_files($files) {
+  $parsed_files = array();
+  foreach ($files as $filename => $file) {
+    if (file_exists($filename)) {
+      $hash = hash_file('sha256', $filename);
+      if (empty($file['hash']) || $file['hash'] != $hash) {
+        // Delete registry entries for this file, so we can insert the new resources.
+        db_query("DELETE FROM {autoload_registry} WHERE filename = '%s'", $filename);
+        $file['hash'] = $hash;
+        $parsed_files[$filename] = $file;
+      }
+    }
+  }
+  foreach ($parsed_files as $filename => $file) {
+    _autoload_registry_parse_file($filename, file_get_contents($filename), $file['module'], $file['weight']);
+    db_query("UPDATE {autoload_registry_file} SET hash = '%s' WHERE filename = '%s'", $file['hash'], $filename);
+    if (!db_affected_rows()) {
+      db_query("INSERT INTO {autoload_registry_file} (filename, hash) VALUES ('%s', '%s')", $filename, $file['hash']);
+    }
+  }
+  return array_keys($parsed_files);
+}
Index: autoloadtest/autoloadtest.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/autoload/autoloadtest/autoloadtest.module,v
retrieving revision 1.1
diff -u -p -r1.1 autoloadtest.module
--- autoloadtest/autoloadtest.module	3 Oct 2008 05:43:31 -0000	1.1
+++ autoloadtest/autoloadtest.module	22 Aug 2010 22:02:06 -0000
@@ -1,37 +1,36 @@
 <?php
 // $Id: autoloadtest.module,v 1.1 2008/10/03 05:43:31 crell Exp $
 
+/**
+ * Implements hook_autoload_info().
+ */
 function autoloadtest_autoload_info() {
-  return array(
-    'AutoloadTestClass' => array(
-      'file' => 'autoloadtest.classes.inc',
-    ),
+  $classes['AutoloadTestClass'] = array(
+    'file' => 'autoloadtest.classes.incorrect.inc',
   );
 }
 
-function autoloadtest_autoload_info_alter($classes) {
-  dpm($classes);
+/**
+ * Implements hook_autoload_info_alter().
+ */
+function autoloadtest_autoload_info_alter(&$classes) {
+  $classes['AutoloadTestClass']['file'] = 'autoload.classes.inc';
 }
 
-
+/**
+ * Implements hook_autoload_menu().
+ */
 function autoloadtest_menu() {
-
-  $items = array();
-
   $items['autoloadtest'] = array(
     'title' => 'Autoload test',
     'type' => MENU_NORMAL_ITEM,
     'access arguments' => array('access content'),
     'page callback' => 'autoloadtest_page',
   );
-
   return $items;
 }
 
 function autoloadtest_page() {
-
   $test = new AutoloadTestClass();
-
   return $test->test();
-
 }
