? .cache
? .git
? .project
? .settings
? empty
? file_255551_0.patch
? file_30520_6.patch
? logs
? modules/file
? sites/all/modules
? sites/default/files
? sites/default/settings.php
? sites/default/test
Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.145
diff -u -p -r1.145 install.php
--- install.php	20 Nov 2008 06:56:16 -0000	1.145
+++ install.php	22 Nov 2008 17:26:13 -0000
@@ -409,7 +409,7 @@ function install_settings_form_submit($f
  * Find all .profile files.
  */
 function install_find_profiles() {
-  return file_scan_directory('./profiles', '/\.profile$/', '/(\.\.?|CVS)$/', 0, TRUE, 'name', 0);
+  return file_scan_directory('./profiles', '/\.profile$/', array('key' => 'name'));
 }
 
 /**
@@ -495,7 +495,7 @@ function install_select_profile_form(&$f
  * Find all .po files for the current profile.
  */
 function install_find_locales($profilename) {
-  $locales = file_scan_directory('./profiles/' . $profilename . '/translations', '/\.po$/', '/(\.\.?|CVS)$/', 0, FALSE);
+  $locales = file_scan_directory('./profiles/' . $profilename . '/translations', '/\.po$/', array('recurse' => FALSE));
   array_unshift($locales, (object) array('name' => 'en'));
   return $locales;
 }
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.829
diff -u -p -r1.829 common.inc
--- includes/common.inc	22 Nov 2008 13:55:27 -0000	1.829
+++ includes/common.inc	22 Nov 2008 17:26:34 -0000
@@ -2131,7 +2131,7 @@ function _drupal_load_stylesheet($matche
  * Delete all cached CSS files.
  */
 function drupal_clear_css_cache() {
-  file_scan_directory(file_create_path('css'), '/.*/', '/(\.\.?|CVS)$/', 'file_unmanaged_delete', TRUE);
+  file_scan_directory(file_create_path('css'), '/.*/', array('callback' => 'file_unmanaged_delete'));
 }
 
 /**
@@ -2568,7 +2568,7 @@ function drupal_build_js_cache($files, $
  * Delete all cached JS files.
  */
 function drupal_clear_js_cache() {
-  file_scan_directory(file_create_path('js'), '/.*/', '/(\.\.?|CVS)$/', 'file_unmanaged_delete', TRUE);
+  file_scan_directory(file_create_path('js'), '/.*/', array('callback' => 'file_unmanaged_delete'));
   variable_set('javascript_parsed', array());
 }
 
@@ -2939,7 +2939,7 @@ function drupal_system_listing($mask, $d
 
   // Get current list of items
   foreach ($searchdir as $dir) {
-    $files = array_merge($files, file_scan_directory($dir, $mask, '/(\.\.?|CVS)$/', 0, TRUE, $key, $min_depth));
+    $files = array_merge($files, file_scan_directory($dir, $mask, array('key' => $key, 'min_depth' => $min_depth)));
   }
 
   return $files;
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.145
diff -u -p -r1.145 file.inc
--- includes/file.inc	16 Nov 2008 19:41:14 -0000	1.145
+++ includes/file.inc	22 Nov 2008 17:26:34 -0000
@@ -1258,51 +1258,65 @@ function file_download() {
  *   The base directory for the scan, without trailing slash.
  * @param $mask
  *   The preg_match() regular expression of the files to find.
- * @param $nomask
- *   The preg_match() regular expression of the files to ignore.
- * @param $callback
- *   The callback function to call for each match.
- * @param $recurse
- *   When TRUE, the directory scan will recurse the entire tree
- *   starting at the provided directory.
- * @param $key
- *   The key to be used for the returned array of files. Possible
- *   values are "filename", for the path starting with $dir,
- *   "basename", for the basename of the file, and "name" for the name
- *   of the file without an extension.
- * @param $min_depth
- *   Minimum depth of directories to return files from.
+ * @param $options
+ *   An associative array of additional options, with the following keys:
+ *   - 'nomask'
+ *     The preg_match() regular expression of the files to ignore. Defaults to
+ *     '/(\.\.?|CVS)$/'.
+ *   - 'callback'
+ *     The callback function to call for each match. There is no default
+ *     callback.
+ *   - 'recurse'
+ *     When TRUE, the directory scan will recurse the entire tree starting at
+ *     the provided directory. Defaults to TRUE.
+ *   - 'key'
+ *     The key to be used for the returned array of files. Possible values are
+ *     "filename", for the path starting with $dir, "basename", for the
+ *     basename of the file, and "name" for the name of the file without an
+ *     extension. Defaults to 'filename'.
+ *   - 'min_depth'
+ *     Minimum depth of directories to return files from. Defaults to 0.
  * @param $depth
  *   Current depth of recursion. This parameter is only used internally and
  *   should not be passed.
  * @return
  *   An associative array (keyed on the provided key) of objects with
- *   "path", "basename", and "name" members corresponding to the
+ *   "filename", "basename", and "name" members corresponding to the
  *   matching files.
  */
-function file_scan_directory($dir, $mask, $nomask = '/(\.\.?|CVS)$/', $callback = 0, $recurse = TRUE, $key = 'filename', $min_depth = 0, $depth = 0) {
-  $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename');
+function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+  // Merge in defaults.
+  $options += array(
+    'nomask' => '/(\.\.?|CVS)$/',
+    'callback' => 0,
+    'recurse' => TRUE,
+    'key' => 'filename',
+    'min_depth' => 0,
+  );
+
+  $options['key'] = (in_array($options['key'], array('filename', 'basename', 'name')) ? $options['key'] : 'filename');
   $files = array();
 
   if (is_dir($dir) && $handle = opendir($dir)) {
     while (FALSE !== ($file = readdir($handle))) {
-      if (!preg_match($nomask, $file) && $file[0] != '.') {
-        if (is_dir("$dir/$file") && $recurse) {
+      if (!preg_match($options['nomask'], $file) && $file[0] != '.') {
+        if (is_dir("$dir/$file") && $options['recurse']) {
           // Give priority to files in this folder by merging them in after any subdirectory files.
-          $files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files);
+          $files = array_merge(file_scan_directory("$dir/$file", $mask, $options, $depth + 1), $files);
         }
-        elseif ($depth >= $min_depth && preg_match($mask, $file)) {
+        elseif ($depth >= $options['min_depth'] && preg_match($mask, $file)) {
           // Always use this match over anything already set in $files with the
-          // same $$key.
+          // same $$options['key'].
           $filename = "$dir/$file";
           $basename = basename($file);
           $name = substr($basename, 0, strrpos($basename, '.'));
-          $files[$$key] = new stdClass();
-          $files[$$key]->filename = $filename;
-          $files[$$key]->basename = $basename;
-          $files[$$key]->name = $name;
-          if ($callback) {
-            $callback($filename);
+          $files[${$options['key']}] = (object) array(
+            'filename' => $filename,
+            'basename' => $basename,
+            'name' => $name,
+          );
+          if ($options['callback']) {
+            $options['callback']($filename);
           }
         }
       }
Index: includes/install.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.inc,v
retrieving revision 1.76
diff -u -p -r1.76 install.inc
--- includes/install.inc	16 Nov 2008 23:44:47 -0000	1.76
+++ includes/install.inc	22 Nov 2008 17:26:34 -0000
@@ -212,7 +212,7 @@ function drupal_detect_database_types() 
   // Because we have no registry yet, we need to also include the install.inc
   // file for the driver explicitly.
 
-  foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', '/(\.\.?|CVS)$/', 0, FALSE) as $file) {
+  foreach (file_scan_directory(DRUPAL_ROOT . '/includes/database', '/^[a-z]*$/i', array('recurse' => FALSE)) as $file) {
     include_once "{$file->filename}/install.inc";
     include_once "{$file->filename}/database.inc";
     $drivers[$file->basename] = $file->filename;
Index: includes/locale.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/locale.inc,v
retrieving revision 1.195
diff -u -p -r1.195 locale.inc
--- includes/locale.inc	16 Nov 2008 19:41:14 -0000	1.195
+++ includes/locale.inc	22 Nov 2008 17:27:12 -0000
@@ -2485,7 +2485,7 @@ function locale_batch_by_language($langc
     // with names ending with $langcode.po. This allows for filenames
     // like node-module.de.po to let translators use small files and
     // be able to import in smaller chunks.
-    $files = array_merge($files, file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)' . $langcode . '\.po$/', '/(\.\.?|CVS)$/', 0, FALSE));
+    $files = array_merge($files, file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)' . $langcode . '\.po$/', array('recurse' => FALSE)));
     $components[] = $component->name;
   }
 
@@ -2517,7 +2517,7 @@ function locale_batch_by_component($comp
         // as $langcode.po or with names ending with $langcode.po. This allows
         // for filenames like node-module.de.po to let translators use small
         // files and be able to import in smaller chunks.
-        $files = array_merge($files, file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)(' . $language_list . ')\.po$/', '/(\.\.?|CVS)$/', 0, FALSE));
+        $files = array_merge($files, file_scan_directory(dirname($component->filename) . '/translations', '/(^|\.)(' . $language_list . ')\.po$/', array('recurse' => FALSE)));
       }
     }
     return _locale_batch_build($files, $finished);
Index: modules/simpletest/tests/file.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/file.test,v
retrieving revision 1.12
diff -u -p -r1.12 file.test
--- modules/simpletest/tests/file.test	16 Nov 2008 19:41:14 -0000	1.12
+++ modules/simpletest/tests/file.test	22 Nov 2008 17:27:18 -0000
@@ -15,6 +15,32 @@ function file_test_validator($file, $err
 }
 
 /**
+ * Helper function for testing file_scan_directory().
+ *
+ * Each time the funciton is called the file is stored in a static variable.
+ * When the function is called with $reset parameter TRUE the cache is cleared
+ * and the results returned.
+ *
+ * @param $file
+ *   File object
+ * @param $reset
+ *   Boolean indicating that the stored files should be removed and returned.
+ * @return
+ *   An array of all previous $file parameters since $reset was last called.
+ */
+function file_test_file_scan_callback($file, $reset = FALSE) {
+  static $files = array();
+
+  if ($reset) {
+    $ret = $files;
+    $files = array();
+    return $ret;
+  }
+
+  $files[] = $file;
+}
+
+/**
  * Base class for file tests that adds some additional file specific
  * assertions and helper functions.
  */
@@ -545,9 +571,6 @@ class FileDirectoryTest extends FileTest
  * Tests the file_scan_directory() function.
  */
 class FileScanDirectoryTest extends FileTestCase {
-  /**
-   * Implementation of getInfo().
-   */
   function getInfo() {
     return array(
       'name' => t('File scan directory'),
@@ -556,18 +579,63 @@ class FileScanDirectoryTest extends File
     );
   }
 
+  function setUp() {
+    parent::setUp();
+    $this->path = $this->original_file_directory . '/simpletest';
+  }
+
+  /**
+   * Check the format of the returned values.
+   */
+  function testReturn() {
+    // Grab a listing of all the JS files and check that they're passed to the
+    // callback.
+    $all_files = file_scan_directory($this->path, '/javascript*/');
+    $this->assertEqual(2, count($all_files), t('Found two, expected javascript files.'));
+
+    // Check the first file.
+    $file = reset($all_files);
+    $this->assertEqual(key($all_files), $file->filename, t('Correct array key was used for the first returned file.'));
+    $this->assertEqual($file->filename, $this->path . '/javascript-1.txt', t('First file name was set correctly.'));
+    $this->assertEqual($file->basename, 'javascript-1.txt', t('First basename was set correctly'));
+    $this->assertEqual($file->name, 'javascript-1', t('First name was set correctly.'));
+
+    // Check the second file.
+    $file = next($all_files);
+    $this->assertEqual(key($all_files), $file->filename, t('Correct array key was used for the second returned file.'));
+    $this->assertEqual($file->filename, $this->path . '/javascript-2.script', t('Second file name was set correctly.'));
+    $this->assertEqual($file->basename, 'javascript-2.script', t('Second basename was set correctly'));
+    $this->assertEqual($file->name, 'javascript-2', t('Second name was set correctly.'));
+  }
+
+  /**
+   * Check that the callback function is called correctly.
+   */
+  function testCallback() {
+    // When nothing is matched nothing should be  passed to the callback.
+    $all_files = file_scan_directory($this->path, '/NONEXISTINGFILENAME/', array('callback' => 'file_test_file_scan_callback'));
+    $this->assertEqual(0, count($all_files), t('No files were found.'));
+    $results = file_test_file_scan_callback(NULL, TRUE);
+    $this->assertEqual(0, count($results), t('No files were passed to the callback.'));
+
+    // Grab a listing of all the JS files and check that they're passed to the
+    // callback.
+    $all_files = file_scan_directory($this->path, '/javascript*/', array('callback' => 'file_test_file_scan_callback'));
+    $this->assertEqual(2, count($all_files), t('Found two, expected javascript files.'));
+    $results = file_test_file_scan_callback(NULL, TRUE);
+    $this->assertEqual(2, count($results), t('Files were passed to the callback.'));
+  }
+
   /**
    * Check that the no-mask parameter is honored.
    */
   function testNoMask() {
-    $path = $this->original_file_directory . '/simpletest';
-
     // Grab a listing of all the JS files.
-    $all_files = file_scan_directory($path, '/javascript*/');
+    $all_files = file_scan_directory($this->path, '/javascript*/');
     $this->assertEqual(2, count($all_files), t('Found two, expected javascript files.'));
 
     // Now use the nomast parameter to filter out the .script file.
-    $filtered_files = file_scan_directory($path, '/javascript*/', '/.script$/');
+    $filtered_files = file_scan_directory($this->path, '/javascript*/', array('nomask' => '/.script$/'));
     $this->assertEqual(1, count($filtered_files), t('Filtered correctly.'));
   }
 }
