1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gnome-vfs-configuration.c - Handling of the GNOME Virtual File System
5 Copyright (C) 1999 Free Software Foundation
7 The Gnome Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The Gnome Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the Gnome Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Author: Ettore Perazzoli <ettore@gnu.org> */
25 #include "gnome-vfs-configuration.h"
29 #include <glib/ghash.h>
30 #include <glib/glist.h>
31 #include <glib/gmem.h>
32 #include <glib/gmessages.h>
33 #include <glib/gstrfuncs.h>
34 #include <glib/gthread.h>
35 #include <glib/gutils.h>
36 #include "gnome-vfs-i18n.h"
37 #include "gnome-vfs-private.h"
44 typedef struct _Configuration Configuration;
45 struct _Configuration {
46 GHashTable *method_to_module_path;
51 typedef struct _ModulePathElement ModulePathElement;
52 struct _ModulePathElement {
58 typedef struct _VfsDirSource VfsDirSource;
59 struct _VfsDirSource {
62 unsigned int valid : 1;
66 static Configuration *configuration = NULL;
68 G_LOCK_DEFINE_STATIC (configuration);
69 #define MAX_CFG_FILES 128
73 static ModulePathElement *
74 module_path_element_new (const char *method_name,
78 ModulePathElement *new;
80 new = g_new (ModulePathElement, 1);
81 new->method_name = g_strdup (method_name);
82 new->path = g_strdup (path);
83 new->args = g_strdup (args);
89 module_path_element_free (ModulePathElement *module_path)
91 g_free (module_path->method_name);
92 g_free (module_path->path);
93 g_free (module_path->args);
98 vfs_dir_source_new (const char *dirname)
102 new = g_new (VfsDirSource, 1);
103 new->dirname = g_strdup (dirname);
109 vfs_dir_source_free (VfsDirSource *vfs_source)
111 g_free (vfs_source->dirname);
118 hash_free_module_path (gpointer value)
120 ModulePathElement *module_path;
122 module_path = (ModulePathElement *) value;
123 module_path_element_free (module_path);
126 /* Destroy configuration information. */
128 configuration_destroy (Configuration *configuration)
130 g_return_if_fail (configuration != NULL);
132 g_hash_table_destroy (configuration->method_to_module_path);
133 g_list_foreach (configuration->directories, (GFunc) vfs_dir_source_free, NULL);
134 g_list_free (configuration->directories);
135 g_free (configuration);
140 /* This reads a line and handles backslashes at the end of the line to join
143 read_line (FILE *stream,
148 #define START_BUFFER_SIZE 1024
163 *n = START_BUFFER_SIZE;
166 *line_return = g_realloc (*line_return, *n);
172 if (c == EOF || (c == '\n' && ! backslash)) {
173 (*line_return)[pos] = 0;
177 if (c == '\\' && ! backslash) {
179 } else if (c != '\n') {
181 (*line_return)[pos++] = '\\';
182 (*line_return)[pos] = c;
187 #undef START_BUFFER_SIZE
191 remove_comment (gchar *buf)
195 p = strchr (buf, '#');
201 parse_line (Configuration *configuration,
204 const gchar *file_name,
217 string_len = strlen (line_buffer);
218 if (string_len != line_len) {
219 g_warning (_("%s:%d contains NUL characters."),
220 file_name, line_number);
224 remove_comment (line_buffer);
225 line_buffer = g_strstrip (line_buffer);
229 method_start = line_buffer;
232 if (*p == ' ' || *p == '\t' || *p == ':') {
235 if (p == method_start) {
236 g_warning (_("%s:%d contains no method name."),
237 file_name, line_number);
242 method_name = g_strndup (method_start,
244 method_list = g_list_prepend (method_list, method_name);
246 while (*p == ' ' || *p == '\t')
260 while (*p && g_ascii_isspace (*p))
264 if (method_list != NULL) {
265 g_warning (_("%s:%d contains no module name."),
266 file_name, line_number);
276 while(*p && !g_ascii_isspace (*p)) p++;
281 while(*p && g_ascii_isspace (*p)) p++;
286 for (lp = method_list; lp != NULL; lp = lp->next) {
287 ModulePathElement *element;
290 method_name = lp->data;
291 element = module_path_element_new (method_name, module_name, args);
292 g_hash_table_insert (configuration->method_to_module_path,
293 method_name, element);
299 if (method_list != NULL)
300 g_list_free (method_list);
304 /* FIXME bugzilla.eazel.com 1139:
305 maybe we should return FALSE if any errors during parsing happen so
306 that we abort immediately, but this sounds a bit too overkill. */
308 parse_file (Configuration *configuration,
309 const gchar *file_name)
313 guint line_buffer_size;
316 f = fopen (file_name, "r");
318 g_warning (_("Configuration file `%s' was not found: %s"),
319 file_name, strerror (errno));
324 line_buffer_size = 0;
330 line_len = read_line (f, &line_buffer, &line_buffer_size,
334 parse_line (configuration, line_buffer, line_len, file_name,
336 line_number += lines_read;
339 g_free (line_buffer);
347 configuration_load (void)
349 gchar *file_names[MAX_CFG_FILES + 1];
354 configuration->method_to_module_path = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, hash_free_module_path);
356 /* Go through the list of configuration directories and build up a list of config files */
357 for (list = configuration->directories; list && i < MAX_CFG_FILES; list = list->next) {
358 VfsDirSource *dir_source = (VfsDirSource *)list->data;
361 if (stat (dir_source->dirname, &dir_source->s) == -1)
364 dirh = opendir (dir_source->dirname);
368 while ((dent = readdir(dirh)) && i < MAX_CFG_FILES) {
370 ctmp = strstr(dent->d_name, ".conf");
371 if(!ctmp || strcmp(ctmp, ".conf"))
373 file_names[i] = g_strdup_printf ("%s/%s", dir_source->dirname, dent->d_name);
378 file_names[i] = NULL;
380 /* Now read these cfg files */
381 for(i = 0; file_names[i]; i++) {
382 /* FIXME: should we try to catch errors? */
383 parse_file (configuration, file_names[i]);
384 g_free (file_names[i]);
390 add_directory_internal (const char *dir)
392 VfsDirSource *dir_source = vfs_dir_source_new (dir);
394 configuration->directories = g_list_prepend (configuration->directories, dir_source);
398 _gnome_vfs_configuration_add_directory (const char *dir)
400 G_LOCK (configuration);
401 if (configuration == NULL) {
402 g_warning ("_gnome_vfs_configuration_init must be called prior to adding a directory.");
403 G_UNLOCK (configuration);
407 add_directory_internal (dir);
409 G_UNLOCK (configuration);
414 install_path_list (const gchar *environment_path)
416 const char *p, *oldp;
418 oldp = environment_path;
422 p = strchr (oldp, ':');
426 add_directory_internal (oldp);
430 elem = g_strndup (oldp, p - oldp);
431 add_directory_internal (elem);
441 _gnome_vfs_configuration_init (void)
444 char *environment_path;
445 const char *home_dir;
447 G_LOCK (configuration);
448 if (configuration != NULL) {
449 G_UNLOCK (configuration);
453 configuration = g_new0 (Configuration, 1);
455 add_directory_internal (GNOME_VFS_MODULE_CFGDIR);
456 environment_path = getenv ("GNOME_VFS_MODULE_CONFIG_PATH");
457 if (environment_path != NULL) {
458 install_path_list (environment_path);
461 home_dir = g_get_home_dir ();
462 if (home_dir != NULL) {
463 home_config = g_strdup_printf ("%s%c%s",
466 ".gnome2/vfs/modules");
467 add_directory_internal (home_config);
468 g_free (home_config);
471 configuration_load ();
473 G_UNLOCK (configuration);
475 if (configuration == NULL) {
483 _gnome_vfs_configuration_uninit (void)
485 G_LOCK (configuration);
486 if (configuration == NULL) {
487 G_UNLOCK (configuration);
491 configuration_destroy (configuration);
492 configuration = NULL;
493 G_UNLOCK (configuration);
499 time_t now = time (NULL);
501 gboolean need_reload = FALSE;
504 /* only check every 5 seconds minimum */
505 if (configuration->last_checked + 5 >= now)
508 for (list = configuration->directories; list; list = list->next) {
509 VfsDirSource *dir_source = (VfsDirSource *) list->data;
510 if (stat (dir_source->dirname, &s) == -1)
512 if (s.st_mtime != dir_source->s.st_mtime) {
518 configuration->last_checked = now;
523 configuration->last_checked = time (NULL);
525 g_hash_table_destroy (configuration->method_to_module_path);
526 configuration_load ();
530 _gnome_vfs_configuration_get_module_path (const gchar *method_name, const char ** args)
532 ModulePathElement *element;
534 g_return_val_if_fail (method_name != NULL, NULL);
536 G_LOCK (configuration);
538 if (configuration != NULL) {
540 element = g_hash_table_lookup
541 (configuration->method_to_module_path, method_name);
543 /* This should never happen. */
544 g_warning ("Internal error: the configuration system was not initialized. Did you call _gnome_vfs_configuration_init?");
548 G_UNLOCK (configuration);
554 *args = element->args;
555 return element->path;
559 add_method_to_list(const gchar *key, gpointer value, GList **methods_list)
561 *methods_list = g_list_append(*methods_list, g_strdup(key));
565 _gnome_vfs_configuration_get_methods_list (void)
567 GList *methods_list = NULL;
569 G_LOCK (configuration);
570 if (configuration != NULL) {
572 g_hash_table_foreach(configuration->method_to_module_path,
573 (GHFunc)add_method_to_list, &methods_list);
575 /* This should never happen. */
579 G_UNLOCK (configuration);