Index: INSTALL.txt =================================================================== RCS file: /cvs/drupal/drupal/INSTALL.txt,v retrieving revision 1.4 diff -u -r1.4 INSTALL.txt --- INSTALL.txt 17 Oct 2004 18:38:22 -0000 1.4 +++ INSTALL.txt 24 Nov 2004 18:27:34 -0000 @@ -103,15 +103,8 @@ 4. CONNECTING DRUPAL - Drupal server options are specified in includes/conf.php. - - Drupal allows for multiple virtual host installations; to configure - a virtual server host, you can create the configuration file - - includes/www.example.com.php - - where www.example.com is your website's URL. - + The default configuration can be found in the + 'sites/default/config.php' file within your Drupal installation. Before you can run Drupal, you must set the database URL and the base URL to the web site. Open the configuration file and edit the $db_url line to match the database defined in the previous steps: @@ -121,6 +114,58 @@ Set $base_url to match the address to your web site: $base_url = "http://www.example.com"; + + In addition, a single Drupal installation can host several + Drupal-powered sites, each with its own individual configuration. + Additional site configurations are created in subdirectories within + the 'sites' directory. Each site subdirectory must have a + 'config.php' file which specifies the configuration settings. The + easiest way to create additional sites is to copy the 'default' + directory and modify the 'config.php' file as appropriate. The new + directory name is constructed from the site's URL. The + configuration for www.example.com could be in + 'sites/example.com/config.php' (note that 'www.' should be omitted + if users can access your site at http://example.com/). + + Sites do not each have to have a different domain. You can use + subdomains and subdirectories for Drupal sites also. For example, + example.com, sub.example.com, and sub.example.com/site3 can all be + defined as independent Drupal sites. The setup for a configuration + such as this would look like the following: + + sites/default/config.php + sites/example.com/config.php + sites/sub.example.com/config.php + sites/sub.example.com.site3/config.php + + When searching for a site configuration (for example + www.sub.example.com/site3), Drupal will search for configuration + files in the following order, using the first configuration file it + finds: + + sites/www.sub.example.com.site3/config.php + sites/sub.example.com.site3/config.php + sites/example.com.site3/config.php + sites/www.sub.example.com/config.php + sites/sub.example.com/config.php + sites/example.com/config.php + sites/default/config.php + + Each site configuration can have its own site-specific modules and + themes that will be made available in addition to those installed + in the standard 'modules' and 'themes' directories. To use + site-specific modules or themes, simply create a 'modules' or + 'themes' directory within the site configuration directory. For + example, if sub.example.dom has a custom theme and a custom module + that should not be accessible to other sites, the setup would look + like this: + + sites/sub.example.com/: + config.php + themes/: + custom_theme + modules/: + custom_module NOTE: for more information about multiple virtual hosts or the configuration settings, consult the Drupal handbook at drupal.org. Index: database/database.mysql =================================================================== RCS file: /cvs/drupal/drupal/database/database.mysql,v retrieving revision 1.159 diff -u -r1.159 database.mysql --- database/database.mysql 16 Nov 2004 18:46:48 -0000 1.159 +++ database/database.mysql 24 Nov 2004 18:27:35 -0000 @@ -767,11 +767,15 @@ INSERT INTO system VALUES ('modules/admin.module','admin','module','',1,0,0); INSERT INTO system VALUES ('modules/block.module','block','module','',1,0,0); INSERT INTO system VALUES ('modules/comment.module','comment','module','',1,0,0); +INSERT INTO system VALUES ('modules/filter.module','filter','module','',1,0,0); INSERT INTO system VALUES ('modules/help.module','help','module','',1,0,0); INSERT INTO system VALUES ('modules/node.module','node','module','',1,0,0); INSERT INTO system VALUES ('modules/page.module','page','module','',1,0,0); INSERT INTO system VALUES ('modules/story.module','story','module','',1,0,0); +INSERT INTO system VALUES ('modules/system.module','system','module','',1,0,0); INSERT INTO system VALUES ('modules/taxonomy.module','taxonomy','module','',1,0,0); +INSERT INTO system VALUES ('modules/user.module','user','module','',1,0,0); +INSERT INTO system VALUES ('modules/watchdog.module','watchdog','module','',1,0,0); INSERT INTO system VALUES ('themes/bluemarine/xtemplate.xtmpl','bluemarine','theme','themes/engines/xtemplate/xtemplate.engine',1,0,0); INSERT INTO system VALUES ('themes/engines/xtemplate/xtemplate.engine','xtemplate','theme_engine','',1,0,0); INSERT INTO users (uid, name, mail) VALUES ('0', '', ''); Index: database/database.pgsql =================================================================== RCS file: /cvs/drupal/drupal/database/database.pgsql,v retrieving revision 1.95 diff -u -r1.95 database.pgsql --- database/database.pgsql 16 Nov 2004 18:46:48 -0000 1.95 +++ database/database.pgsql 24 Nov 2004 18:27:35 -0000 @@ -751,11 +751,15 @@ INSERT INTO system VALUES ('modules/admin.module','admin','module','',1,0,0); INSERT INTO system VALUES ('modules/block.module','block','module','',1,0,0); INSERT INTO system VALUES ('modules/comment.module','comment','module','',1,0,0); +INSERT INTO system VALUES ('modules/filter.module','filter','module','',1,0,0); INSERT INTO system VALUES ('modules/help.module','help','module','',1,0,0); INSERT INTO system VALUES ('modules/node.module','node','module','',1,0,0); INSERT INTO system VALUES ('modules/page.module','page','module','',1,0,0); INSERT INTO system VALUES ('modules/story.module','story','module','',1,0,0); +INSERT INTO system VALUES ('modules/system.module','system','module','',1,0,0); INSERT INTO system VALUES ('modules/taxonomy.module','taxonomy','module','',1,0,0); +INSERT INTO system VALUES ('modules/user.module','user','module','',1,0,0); +INSERT INTO system VALUES ('modules/watchdog.module','watchdog','module','',1,0,0); INSERT INTO system VALUES ('themes/bluemarine/xtemplate.xtmpl','bluemarine','theme','themes/engines/xtemplate/xtemplate.engine',1,0,0); INSERT INTO system VALUES ('themes/engines/xtemplate/xtemplate.engine','xtemplate','theme_engine','',1,0,0); Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.33 diff -u -r1.33 bootstrap.inc --- includes/bootstrap.inc 21 Nov 2004 08:25:17 -0000 1.33 +++ includes/bootstrap.inc 24 Nov 2004 18:27:35 -0000 @@ -12,25 +12,42 @@ /** * Locate the appropriate configuration file. * - * Try finding a matching configuration file by stripping the website's - * URI from left to right. If no configuration file is found, return the - * default value, "conf". + * Try finding a matching configuration directory by stripping the + * website's hostname from left to right and pathname from right to + * left. If no configuration file is found, return a default value + * '$confdir/default'. Example for a ficticious site installed at + * http://www.drupal.org/test: + * + * 1. www.drupal.org.test + * 2. drupal.org.test + * 3. www.drupal.org + * 4. drupal.org + * 5. default */ function conf_init() { - $uri = $_SERVER['PHP_SELF']; + static $conf = ''; - $file = strtolower(strtr($_SERVER['HTTP_HOST'] . substr($uri, 0, strrpos($uri, '/')), '/:', '..')); + if ($conf) { + return $conf; + } - while (strlen($file) > 4) { - if (file_exists('includes/'. $file .'.php')) { - return $file; - } - else { - $file = substr($file, strpos($file, '.') + 1); + $uri = explode('/', $_SERVER['PHP_SELF']); + $server = explode('.', $_SERVER['HTTP_HOST']); + $confdir = 'sites'; + + for ($i = count($uri) - 1; $i > 0; $i--) { + for ($j = count($server); $j > 1; $j--) { + $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i)); + + if (file_exists("$confdir/$dir/config.php")) { + $conf = "$confdir/$dir"; + return $conf; + } } } - return 'conf'; + $conf = "$confdir/default"; + return $conf; } /** @@ -442,7 +459,7 @@ unset($conf); $config = conf_init(); -include_once "includes/$config.php"; +include_once "$config/config.php"; include_once 'includes/database.inc'; include_once 'includes/session.inc'; include_once 'includes/module.inc'; Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.403 diff -u -r1.403 common.inc --- includes/common.inc 23 Nov 2004 23:11:58 -0000 1.403 +++ includes/common.inc 24 Nov 2004 18:27:36 -0000 @@ -1836,6 +1836,100 @@ return $output; } +/** + * Returns and optionally sets the filename for a system item (module, + * theme, etc.). The filename, whether provided, cached, or retrieved + * from the database, is only returned if the file exists. + * + * @param $type + * The type of the item (i.e. theme, theme_engine, module). + * @param $name + * The name of the item for which the filename is requested. + * @param $filename + * The filename of the item if it is to be set explicitly rather + * than by consulting the database. + * + * @return + * The filename of the requested item. + */ +function drupal_get_filename($type, $name, $filename = NULL) { + static $files = array(); + + if (!$files[$type]) { + $files[$type] = array(); + } + + if ($filename && file_exists($filename)) { + $files[$type][$name] = $filename; + } + elseif ($files[$type][$name]) { + // nothing + } + elseif (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file)) { + $files[$type][$name] = $file; + } + else { + $config = conf_init(); + $dir = (($type == 'theme_engine') ? 'themes/engines' : "${type}s"); + $file = "$name.$type"; + + foreach (array("$config/$dir/$file", "$config/$dir/$name/$file", "$dir/$file", "$dir/$name/$file") as $file) { + if (file_exists($file)) { + $files[$type][$name] = $file; + break; + } + } + } + + return $files[$type][$name]; +} + +/** + * Returns the path to a system item (module, theme, etc.). + * + * @param $type + * The type of the item (i.e. theme, theme_engine, module). + * @param $name + * The name of the item for which the path is requested. + * + * @return + * The path to the requested item. + */ +function drupal_get_path($type, $name) { + return dirname(drupal_get_filename($type, $name)); +} + +/** + * Includes a file with the provided type and name. This prevents + * including a theme, engine, module, etc., more than once. + * + * @param $type + * The type of item to load (i.e. theme, theme_engine, module). + * @param $name + * The name of the item to load. + * + * @return + * TRUE if the item is loaded or has already been loaded. + */ +function drupal_load($type, $name) { + static $files = array(); + + if ($files[$type][$name]) { + return TRUE; + } + + $filename = drupal_get_filename($type, $name); + + if ($filename) { + include_once($filename); + $files[$type][$name] = TRUE; + + return TRUE; + } + + return FALSE; +} + include_once 'includes/theme.inc'; include_once 'includes/pager.inc'; include_once 'includes/menu.inc'; Index: includes/file.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/file.inc,v retrieving revision 1.32 diff -u -r1.32 file.inc --- includes/file.inc 15 Nov 2004 12:04:44 -0000 1.32 +++ includes/file.inc 24 Nov 2004 18:27:36 -0000 @@ -469,39 +469,59 @@ } /** - * Finds all files that match a given mask in a given directory. + * Finds all files that match a given mask in a given + * directory. * - * @param $dir Directory to scan - * @param $mask Regular expression to filter out files. Only filenames that - * match the mask will be returned. - * @param $nomask Array of filenames which should never be returned regardless - * if they match the $mask - * @param $callback Function to call for qualifying file. - * Set to 0 or false if you do not want callbacks. - * @param $recurse When true directory scan will recurse the entire tree starting at $dir - * @return Array of qualifying files + * @param $dir + * The base directory for the scan. + * @param $mask + * The regular expression of the files to find. + * @param $nomask + * An array of files/directories 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. + * + * @return + * An associative array (keyed on the provided key) of objects with + * "path", "basename", and "name" members corresponding to the + * matching files. */ -function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE) { +function file_scan_directory($dir, $mask, $nomask = array('.', '..', 'CVS'), $callback = 0, $recurse = TRUE, $key = 'filename') { + $key = (in_array($key, array('filename', 'basename', 'name')) ? $key : 'filename'); $files = array(); + if (is_dir($dir) && $handle = opendir($dir)) { while ($file = readdir($handle)) { if (!in_array($file, $nomask)) { if (is_dir("$dir/$file") && $recurse) { - $files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback)); + $files = array_merge($files, file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key)); } elseif (ereg($mask, $file)) { - $name = basename($file); - $files["$dir/$file"] = new stdClass(); - $files["$dir/$file"]->filename = "$dir/$file"; - $files["$dir/$file"]->name = substr($name, 0, strrpos($name, '.')); + $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("$dir/$file"); + $callback($filename); } } } } + closedir($handle); } + return $files; } Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.60 diff -u -r1.60 module.inc --- includes/module.inc 7 Nov 2004 22:46:59 -0000 1.60 +++ includes/module.inc 24 Nov 2004 18:27:36 -0000 @@ -61,8 +61,8 @@ // variables, since throttle.module may not be loaded yet. $throttle = ($module->throttle && variable_get('throttle_level', 0) > 0); if (!$throttle) { + drupal_get_filename('module', $module->name, $module->filename); $list[$module->name] = $module->name; - module_set_filename($module->name, $module->filename); } } } @@ -72,85 +72,19 @@ } /** - * Set the filename of a module, for future loading through module_load() - * - * @param $module - * Name of the module which to specify the filename of. - * @param $pa - * Filename of the module named $module. - * @return - * Filename of module, if no $path has been specified. - */ -function module_set_filename($module, $path = null) { - static $list; - - if ($path) { - $list[$module] = $path; - } - else { - return $list[$module] ? $list[$module] : "modules/$module.module"; - } -} - -/** - * Retrieve the filename of a module - * - * @param $module - * Name of the module which to retrieve the filename of. - * @return - * Filename of module. - */ -function module_get_filename($module) { - return module_set_filename($module); -} - -/** - * Retrieve the path of a module - * - * @param $module - * Name of the module which to retrieve the path of. - * @return - * Path of module. - */ -function module_get_path($module) { - return dirname(module_get_filename($module)); -} - -/** - * Load a module into Drupal, but check first whether a module by the same name - * has been loaded, and that the filename being included exists. - * @param $module - * The name of the module to be loaded. - * @return - * TRUE if the load was successful. - */ -function module_load($module) { - static $loaded = array(); - - if (!$loaded[$module]) { - $filename = module_get_filename($module); - if (file_exists($filename)) { - include_once($filename); - $loaded[$module] = $filename; - return true; - } - } - return false; -} - - -/** * Load all the modules that have been enabled in the system table. * * @return - * TRUE if all modules were loaded successfully + * TRUE if all modules were loaded successfully. */ function module_load_all() { $list = module_list(); - $status = true; + $status = TRUE; + foreach ($list as $module) { - $status &= module_load($module); + $status = (drupal_load('module', $module) && $status); } + return $status; } Index: modules/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system.module,v retrieving revision 1.186 diff -u -r1.186 system.module --- modules/system.module 15 Nov 2004 11:26:04 -0000 1.186 +++ modules/system.module 24 Nov 2004 18:27:37 -0000 @@ -271,177 +271,148 @@ } /** - * Inventory theme engines and insert entries for them into the system table - */ -function system_theme_engine_inventory($directory) { - $engines = array(); - - // Remove all theme engines from the system table - db_query('DELETE FROM {system} WHERE type = \'%s\'', 'theme_engine'); - - // Find theme engines in the directory and insert into database - $files = file_scan_directory($directory. '/engines', '\.engine$'); - - foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); - - $info = new StdClass(); - $info->name = $file->name; - $info->filename = $file->filename; - $engines[$info->name] = $info; - - db_query('INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, 'theme_engine', $filename, 1, 0, 0); - } - return $engines; -} - -/** - * Retrieves an array of a particular type of files (specified by $type) in a particular $directory - * and their current status in the system table. - */ -function system_get_files($search, $type, $directory) { - // Find files in the directory. - $files = file_scan_directory($directory, $search); - - return $files; -} - -/** * Retrieves the current status of an array of files in the system table. */ function system_get_files_database(&$files, $type) { // Extract current files from database. - $result = db_query('SELECT filename, type, status, throttle FROM {system} WHERE type = \'%s\'', $type); + $result = db_query("SELECT name, type, status, throttle FROM {system} WHERE type = '%s'", $type); while ($file = db_fetch_object($result)) { - if (is_object($files[$file->filename])) { + if (is_object($files[$file->name])) { foreach ($file as $key => $value) { - $files[$file->filename]->$key = $value; + if (!$files[$file->name]->$key) { + $files[$file->name]->$key = $value; + } } } } } /** - * Obtains information about each theme in the $files array - * Also updates the system table + * Collect data about all currently available themes */ -function system_obtain_theme_info($files, $directory) { - foreach ($files as $filename => $file) { - $info = new StdClass(); - if ($file->theme) { - // file is a style - $info->description = $file->theme; - $info->style = TRUE; - } - - if (strpos($filename, '.theme')) { - // file is a theme - module_set_filename($file->name, $filename); - module_load($file->name); - $info->description = ''; - $info->prefix = basename($filename, '.theme'); - } - elseif ($info->style && !$file->engine) { - $info->prefix = $info->description; - } - else { - // file is a template - $info->description = $info->style ? $info->description : $file->engine; - $info->template = TRUE; - $info->prefix = basename($file->engine, '.engine'); - } - - $info->filename = $filename; - $info->path = pathinfo($info->filename); - $info->name = str_replace(array($directory .'/'), '', $info->path['dirname']); - $info->shortname = basename($info->name); - $info->screenshot = dirname($info->filename) .'/screenshot.png'; - - $info->status = $file->status; +function system_theme_data() { + // Find themes + $themes = system_listing('\.theme$', 'themes'); - $themes[$info->name] = $info; + // Find theme engines + $engines = system_listing('\.engine$', 'themes/engines'); - // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $info->filename, 'theme'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'theme', $info->filename, $info->status, 0, 0); + // can't iterate over array itself as it uses a copy of the array items + foreach (array_keys($themes) as $key) { + drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); + drupal_load('theme', $themes[$key]->name); + $themes[$key]->description = dirname($themes[$key]->filename); + $themes[$key]->owner = $themes[$key]->filename; + $themes[$key]->prefix = $key; } - return $themes; -} - -/** - * Collect data about all currently available themes - */ -function system_theme_data($directory) { - // Find theme engines - $engines = system_theme_engine_inventory($directory); - // Get current list of themes and their present status in the system table. - $files = system_get_files('\.theme$', 'theme', $directory); + // Remove all theme engines from the system table + db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); // Add templates to the site listing foreach ($engines as $engine) { - foreach (call_user_func($engine->name .'_templates', $directory) as $template) { - $template_files[$template->filename] = $template; - $template_files[$template->filename]->engine = $engine->filename; - foreach ($files as $file) { - // do not double-insert templates with theme files in their directory - if (dirname($template->filename) == dirname($file->filename)) { - unset($template_files[$template->filename]); - } - } + drupal_get_filename('theme_engine', $engine->name, $engine->filename); + drupal_load('theme_engine', $engine->name); + db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0); + + foreach (call_user_func($engine->name . '_templates') as $template) { + $template->template = TRUE; + $template->name = basename(dirname($template->filename)); + $template->basename = $template->name; + $template->description = dirname($template->filename); + $template->owner = $engine->filename; + $template->prefix = $engine->name; + $themes[$template->name] = $template; } } - $files = array_merge($files, $template_files); // Find styles in each theme's directory. - foreach ($files as $file) { - foreach (system_get_files("style.css$", 'theme', dirname($file->filename)) as $style) { + foreach ($themes as $theme) { + foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { // do not double-insert themes with css files in their directory - if (dirname($style->filename) != dirname($file->filename)) { - $style_files[$style->filename] = $style; - $path = pathinfo($file->filename); - $style_files[$style->filename]->theme = str_replace(array($directory .'/'), '', $path['dirname']); - if ($file->engine) { - $style_files[$style->filename]->engine = $file->engine; - } + if (dirname($style->filename) != dirname($theme->filename)) { + $style->style = TRUE; + $style->name = basename(dirname($style->filename)); + $style->description = dirname($style->filename); + $style->owner = $theme->filename; + $style->prefix = $theme->name; + $themes[$style->name] = $style; } } } - $files = array_merge($files, $style_files); // Extract current files from database. - system_get_files_database($files, 'theme'); + system_get_files_database($themes, 'theme'); + + db_query("DELETE FROM {system} WHERE type = 'theme'"); - // Build an array of information about each theme for use in displaying the selection table. - return system_obtain_theme_info($files, $directory); + foreach ($themes as $theme) { + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, 'theme', $theme->filename, $theme->status, 0, 0); + } + + return $themes; +} + +/** + * Returns an array of files objects of the given type from both the + * site-wide directory (i.e. modules/) and site-specific directory + * (i.e. sites/somesite/modules/). The returned array will be keyed + * using the key specified (name, basename, filename). Using name or + * basename will cause site-specific files to shadow files in the + * default directories. That is, if a file with the same name appears + * in both location, only the site-specific version will be included. + * + * @param $mask + * The regular expression of the files to find. + * @param $directory + * The subdirectory name in which the files are found. For example, + * 'modules' will search in both modules/ and + * sites/somesite/modules/. + * @param $key + * The key to be passed to file_scan_directory(). + * + * @return + * An array of file objects of the specified type. + */ +function system_listing($mask, $directory, $key = 'name') { + $config = conf_init(); + $searchdir = array($directory); + $files = array(); + + if (file_exists("$config/$directory")) { + $searchdir[] = "$config/$directory"; + } + + // Get current list of items + foreach ($searchdir as $dir) { + $files = array_merge($files, file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, TRUE, $key)); + } + + return $files; } /** * Generate a list of all the available theme/style combinations. */ function system_theme_listing() { - $directory = 'themes'; - - $themes = system_theme_data($directory); + $themes = system_theme_data(); ksort($themes); - foreach ($themes as $key => $info) { + foreach ($themes as $name => $info) { + $info->screenshot = dirname($info->filename) . '/screenshot.png'; $row = array(); // Screenshot column. - $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->shortname)), '', 'class="screenshot"', false) : t('no screenshot'); + $row[] = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', 'class="screenshot"', false) : t('no screenshot'); // Information field. - $field = ''. $info->shortname .''; - $field .= '
themes/'. $key .''; - $row[] = $field; + $row[] = "$info->name
$info->description"; // enabled, default, and operations columns - $row[] = array('data' => form_checkbox('', 'status]['. $info->filename, 1, $info->status), 'align' => 'center'); - $row[] = array('data' => form_radio('', 'theme_default', $info->filename, (variable_get('theme_default', 'bluemarine') == $key) ? 1 : 0), 'align' => 'center'); - if (function_exists($info->prefix .'_settings') || function_exists($info->prefix .'_features')) { - $row[] = array('data' => l(t('configure'), 'admin/themes/settings/'. str_replace('/', '.', $key)), 'align' => 'center'); + $row[] = array('data' => form_checkbox('', 'status]['. $info->name, 1, $info->status), 'align' => 'center'); + $row[] = array('data' => form_radio('', 'theme_default', $info->name, (variable_get('theme_default', 'bluemarine') == $name) ? 1 : 0), 'align' => 'center'); + if (function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features')) { + $row[] = array('data' => l(t('configure'), 'admin/themes/settings/' . str_replace('/', '.', preg_replace('<^.*themes/(.*)$>', '$1', $info->description))), 'align' => 'center'); } else { $row[] = ''; @@ -459,18 +430,16 @@ * Generate a list of all the available modules, as well as update the system list. */ function system_module_listing() { - $directory = 'modules'; - // Get current list of modules - $files = system_get_files('\.module$', 'module', $directory); + $files = system_listing('\.module$', 'modules'); // Extract current files from database. system_get_files_database($files, 'module'); ksort($files); - $required = array('modules/admin.module', 'modules/block.module', 'modules/filter.module', 'modules/system.module', 'modules/user.module', 'modules/watchdog.module'); - $throttle_required = array_merge($required, array('modules/throttle.module')); + $required = array('admin', 'block', 'filter', 'system', 'user', 'watchdog'); + $throttle_required = array_merge($required, array('throttle')); $header = array(t('Name'), t('Description'), t('Enabled')); if (module_exist('throttle')) { @@ -478,12 +447,11 @@ } foreach ($files as $filename => $file) { - module_set_filename($file->name, $filename); - module_load($file->name); + drupal_get_filename('module', $file->name, $file->filename); + drupal_load('module', $file->name); + + $file->description = module_invoke($file->name, 'help', 'admin/modules#description'); - $info = new StdClass(); - $info->name = module_invoke($file->name, 'help', 'admin/modules#name') ? module_invoke($file->name, 'help', 'admin/modules#name') : $file->name; - $info->description = module_invoke($file->name, 'help', 'admin/modules#description'); // log the critical hooks implemented by this module $bootstrap = 0; foreach (bootstrap_hooks() as $hook) { @@ -494,12 +462,12 @@ } // Update the contents of the system table: - db_query('DELETE FROM {system} WHERE filename = \'%s\' AND type = \'%s\'', $filename, 'module'); - db_query('INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES (\'%s\', \'%s\', \'%s\', \'%s\', %d, %d, %d)', $info->name, $info->description, 'module', $filename, $file->status, $file->throttle, $bootstrap); + db_query("DELETE FROM {system} WHERE name = '%s' AND type = '%s'", $file->name, 'module'); + db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $file->name, $file->description, 'module', $file->filename, $file->status, $file->throttle, $bootstrap); - $row = array($info->name, $info->description, array('data' => (in_array($filename, $required) ? form_hidden('status]['. $filename, 1) . t('required') : form_checkbox('', 'status]['. $filename, 1, $file->status)), 'align' => 'center')); + $row = array($file->name, $file->description, array('data' => (in_array($file->name, $required) ? form_hidden("status][$file->name", 1) . t('required') : form_checkbox('', "status][$file->name", 1, $file->status)), 'align' => 'center')); if (module_exist('throttle')) { - $row[] = array('data' => (in_array($filename, $throttle_required) ? form_hidden('throttle]['. $filename, 0) . t('required') : form_checkbox(NULL, 'throttle]['. $filename, 1, $file->throttle, NULL)), 'align' => 'center'); + $row[] = array('data' => (in_array($file->name, $throttle_required) ? form_hidden("throttle][$file->name", 0) . t('required') : form_checkbox(NULL, "throttle][$file->name", 1, $file->throttle, NULL)), 'align' => 'center'); } $rows[] = $row; } @@ -516,18 +484,17 @@ if ($op == t('Save configuration')) { db_query("UPDATE {system} SET status = 0 WHERE type = '%s'", $edit['type']); - foreach ($edit['status'] as $filename => $status) { + foreach ($edit['status'] as $name => $status) { // Make certain that the default theme is enabled to avoid user error - if (($edit['type'] == 'theme') && ($edit['theme_default'] == $filename)) { + if (($edit['type'] == 'theme') && ($edit['theme_default'] == $name)) { $status = 1; } - db_query("UPDATE {system} SET status = %d, throttle = %d WHERE filename = '%s'", $status, $edit['throttle'][$filename], $filename); + db_query("UPDATE {system} SET status = %d, throttle = %d WHERE type = '%s' AND name = '%s'", $status, $edit['throttle'][$name], $edit['type'], $name); } + if ($edit['type'] == 'theme') { - $path = pathinfo($edit['theme_default']); - $name = str_replace(array('themes/'), '', $path['dirname']); - variable_set('theme_default', $name); + variable_set('theme_default', $edit['theme_default']); } cache_clear_all(); @@ -620,8 +587,8 @@ if ($key) { $settings = theme_get_settings($key); $var = str_replace('/', '_', 'theme_'. $key .'_settings'); - $themes = system_theme_data('themes'); - $features = function_exists($themes[$key]->prefix .'_features') ? call_user_func($themes[$key]->prefix .'_features') : array(); + $themes = system_theme_data(); + $features = function_exists($themes[$key]->prefix . '_features') ? call_user_func($themes[$key]->prefix . '_features') : array(); } else { $settings = theme_get_settings(''); Index: themes/engines/xtemplate/xtemplate.engine =================================================================== RCS file: /cvs/drupal/drupal/themes/engines/xtemplate/xtemplate.engine,v retrieving revision 1.8 diff -u -r1.8 xtemplate.engine --- themes/engines/xtemplate/xtemplate.engine 23 Nov 2004 23:11:59 -0000 1.8 +++ themes/engines/xtemplate/xtemplate.engine 24 Nov 2004 18:27:38 -0000 @@ -10,15 +10,15 @@ function xtemplate_init($template) { // We cannot use the theme() or path_to_theme() functions here if (!class_exists('XTemplate')) { - include_once('themes/engines/xtemplate/xtemplate.inc'); + include_once(dirname(__FILE__) . '/xtemplate.inc'); } $GLOBALS["xtemplate"] = new StdClass(); $GLOBALS['xtemplate']->template = new XTemplate(basename($template->filename), dirname($template->filename)); $GLOBALS['xtemplate']->template->SetNullBlock(' '); // '' doesn't work! } -function xtemplate_templates($directory) { - return file_scan_directory($directory, 'xtemplate.xtmpl$'); +function xtemplate_templates() { + return system_listing('^xtemplate\.xtmpl$', 'themes', 'filename'); } function xtemplate_features() {