Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.165
diff -u -p -r1.165 module.inc
--- includes/module.inc	5 Nov 2009 16:19:25 -0000	1.165
+++ includes/module.inc	5 Nov 2009 22:57:28 -0000
@@ -564,3 +564,67 @@ function drupal_required_modules() {
 
   return $required;
 }
+
+/**
+ * Return a list of modules defining a given .info file property.
+ *
+ * This function builds a list of all modules that are currently registered,
+ * including disabled modules. It can be used to easily find all modules that
+ * define a certain .info file property. For example:
+ * @code
+ *   module_list_by_info(TRUE, array('required'));
+ * @endcode
+ * would list all required Drupal core modules.
+ *
+ * @code
+ *   module_list_by_info('taxonomy', array('dependencies'));
+ * @endcode
+ * would list all modules that require Taxonomy module.
+ *
+ * @param $value
+ *   The value to search for, for example 'TRUE'. If the last parent key defined
+ *   in $parents is an array (such as the 'dependencies' definition), then
+ *   $value is searched in the array of values defined by a module.
+ * @param $parents
+ *   A list of .info file property keys to search $value in, for example
+ *   array('hidden').
+ * @param $simple
+ *   (optional) Boolean whether to return human-readable module names as values
+ *   (TRUE) or fully populated module objects including .info file information
+ *   as values (FALSE). Defaults to TRUE.
+ *
+ * @return
+ *   An associative array containing the machine-readable module name as key,
+ *   and the human-readable module name as value if $simple is TRUE, or a fully
+ *   populated module object if $simple is FALSE.
+ */
+function module_list_by_info($value, $parents, $simple = TRUE) {
+  $modules = array();
+  // @todo Add a fallback to filesystem + .info file parsing if DB is unavailable?
+  $result = db_query("SELECT * FROM {system} WHERE type = 'module'")->fetchAllAssoc('name');
+  foreach ($result as $name => $module) {
+    $module->info = unserialize($module->info);
+    $info = $module->info;
+    foreach ($parents as $parent) {
+      // If the (next) parent is not found, skip to the next module.
+      if (!isset($info[$parent])) {
+        continue 2;
+      }
+      $info = $info[$parent];
+    }
+    // Check whether $info is an array first.
+    if (is_array($info)) {
+      if (in_array($value, $info)) {
+        $modules[$name] = ($simple ? $module->info['name'] : $module);
+      }
+    }
+    // Otherwise, look whether $info matches $value.
+    else {
+      if ($info == $value) {
+        $modules[$name] = ($simple ? $module->info['name'] : $module);
+      }
+    }
+  }
+  return $modules;
+}
+
