summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <withnall@endlessm.com>2018-12-13 16:24:07 +0000
committerPhilip Withnall <pwithnall@endlessos.org>2022-06-17 11:44:53 +0100
commit462198f8972bb9ce73b38942422d25ac9fd3c142 (patch)
treecd3a71ab6df22205c63d90ad02ca53b68b374ca2
parent141482017fbcac64f719da1788607ebe0f8ea0a5 (diff)
xdgmime: Add xdg_mime_set_dirs() method to override XDG envvars
In order to make xdgmime properly relocatable so that unit tests can use it without it reading and modifying the user’s actual xdgmime files, and without the need to call setenv() (and get tied up with thread safety problems), add a xdg_mime_set_dirs() method to allow the dirs to be overridden. They will still default to the values of $XDG_DATA_HOME and $XDG_DATA_DIRS. Signed-off-by: Philip Withnall <withnall@endlessm.com>
-rw-r--r--src/xdgmime.c189
-rw-r--r--src/xdgmime.h2
2 files changed, 128 insertions, 63 deletions
diff --git a/src/xdgmime.c b/src/xdgmime.c
index f585a07..03ab3f5 100644
--- a/src/xdgmime.c
+++ b/src/xdgmime.c
@@ -64,6 +64,8 @@ static XdgCallbackList *callback_list = NULL;
static XdgIconList *icon_list = NULL;
static XdgIconList *generic_icon_list = NULL;
+static char **xdg_dirs = NULL; /* NULL terminated */
+
XdgMimeCache **_caches = NULL;
static int n_caches = 0;
@@ -148,8 +150,8 @@ xdg_mime_init_from_directory (const char *directory,
assert (directory != NULL);
- file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+ file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/mime.cache");
if (stat (file_name, &st) == 0)
{
XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
@@ -168,8 +170,8 @@ xdg_mime_init_from_directory (const char *directory,
}
free (file_name);
- file_name = malloc (strlen (directory) + strlen ("/mime/globs2") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/globs2");
+ file_name = malloc (strlen (directory) + strlen ("/globs2") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/globs2");
if (stat (file_name, &st) == 0)
{
_xdg_mime_glob_read_from_file (global_hash, file_name, TRUE);
@@ -178,8 +180,8 @@ xdg_mime_init_from_directory (const char *directory,
else
{
free (file_name);
- file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+ file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/globs");
if (stat (file_name, &st) == 0)
{
_xdg_mime_glob_read_from_file (global_hash, file_name, FALSE);
@@ -191,8 +193,8 @@ xdg_mime_init_from_directory (const char *directory,
}
}
- file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+ file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/magic");
if (stat (file_name, &st) == 0)
{
_xdg_mime_magic_read_from_file (global_magic, file_name);
@@ -203,69 +205,81 @@ xdg_mime_init_from_directory (const char *directory,
free (file_name);
}
- file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
+ file_name = malloc (strlen (directory) + strlen ("/aliases") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/aliases");
_xdg_mime_alias_read_from_file (alias_list, file_name);
free (file_name);
- file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
+ file_name = malloc (strlen (directory) + strlen ("/subclasses") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/subclasses");
_xdg_mime_parent_read_from_file (parent_list, file_name);
free (file_name);
- file_name = malloc (strlen (directory) + strlen ("/mime/icons") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/icons");
+ file_name = malloc (strlen (directory) + strlen ("/icons") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/icons");
_xdg_mime_icon_read_from_file (icon_list, file_name);
free (file_name);
- file_name = malloc (strlen (directory) + strlen ("/mime/generic-icons") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/generic-icons");
+ file_name = malloc (strlen (directory) + strlen ("/generic-icons") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/generic-icons");
_xdg_mime_icon_read_from_file (generic_icon_list, file_name);
free (file_name);
return FALSE; /* Keep processing */
}
-/* Runs a command on all the directories in the search path */
+/* Set @xdg_dirs from the environment. It must not have been set already. */
static void
-xdg_run_command_on_dirs (XdgDirectoryFunc func,
- void *user_data)
+xdg_init_dirs (void)
{
- const char *xdg_data_home;
- const char *xdg_data_dirs;
+ const char *xdg_data_home, *home, *xdg_data_dirs;
const char *ptr;
+ size_t n_dirs = 0;
+ size_t i, current_dir;
+
+ assert (xdg_dirs == NULL);
xdg_data_home = getenv ("XDG_DATA_HOME");
- if (xdg_data_home)
+ home = getenv ("HOME");
+ xdg_data_dirs = getenv ("XDG_DATA_DIRS");
+
+ if (xdg_data_dirs == NULL)
+ xdg_data_dirs = "/usr/local/share/:/usr/share/";
+
+ /* Work out how many dirs we’re dealing with. */
+ if (xdg_data_home != NULL || home != NULL)
+ n_dirs++;
+ n_dirs++; /* initial entry in @xdg_data_dirs */
+ for (i = 0; xdg_data_dirs[i] != '\0'; i++)
+ if (xdg_data_dirs[i] == ':')
+ n_dirs++;
+
+ xdg_dirs = calloc (n_dirs + 1 /* NULL terminator */, sizeof (char *));
+ current_dir = 0;
+
+ /* $XDG_DATA_HOME */
+ if (xdg_data_home != NULL)
{
- if ((func) (xdg_data_home, user_data))
- return;
+ char *mime_subdir;
+
+ mime_subdir = malloc (strlen (xdg_data_home) + strlen ("/mime/") + 1);
+ strcpy (mime_subdir, xdg_data_home);
+ strcat (mime_subdir, "/mime/");
+
+ xdg_dirs[current_dir++] = mime_subdir;
}
- else
+ else if (home != NULL)
{
- const char *home;
-
- home = getenv ("HOME");
- if (home != NULL)
- {
- char *guessed_xdg_home;
- int stop_processing;
+ char *guessed_xdg_home;
- guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
- strcpy (guessed_xdg_home, home);
- strcat (guessed_xdg_home, "/.local/share/");
- stop_processing = (func) (guessed_xdg_home, user_data);
- free (guessed_xdg_home);
+ guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/mime/") + 1);
+ strcpy (guessed_xdg_home, home);
+ strcat (guessed_xdg_home, "/.local/share/mime/");
- if (stop_processing)
- return;
- }
+ xdg_dirs[current_dir++] = guessed_xdg_home;
}
- xdg_data_dirs = getenv ("XDG_DATA_DIRS");
- if (xdg_data_dirs == NULL)
- xdg_data_dirs = "/usr/local/share/:/usr/share/";
-
+ /* $XDG_DATA_DIRS */
ptr = xdg_data_dirs;
while (*ptr != '\000')
@@ -273,33 +287,82 @@ xdg_run_command_on_dirs (XdgDirectoryFunc func,
const char *end_ptr;
char *dir;
int len;
- int stop_processing;
end_ptr = ptr;
while (*end_ptr != ':' && *end_ptr != '\000')
- end_ptr ++;
+ end_ptr ++;
if (end_ptr == ptr)
- {
- ptr++;
- continue;
- }
+ {
+ ptr++;
+ continue;
+ }
if (*end_ptr == ':')
- len = end_ptr - ptr;
+ len = end_ptr - ptr;
else
- len = end_ptr - ptr + 1;
- dir = malloc (len + 1);
+ len = end_ptr - ptr + 1;
+ dir = malloc (len + strlen ("/mime/") + 1);
strncpy (dir, ptr, len);
dir[len] = '\0';
- stop_processing = (func) (dir, user_data);
- free (dir);
+ strcat (dir, "/mime/");
- if (stop_processing)
- return;
+ xdg_dirs[current_dir++] = dir;
ptr = end_ptr;
}
+
+ /* NULL terminator */
+ xdg_dirs[current_dir] = NULL;
+
+ need_reread = TRUE;
+}
+
+/* Runs a command on all the directories in the search path (@xdg_dirs). */
+static void
+xdg_run_command_on_dirs (XdgDirectoryFunc func,
+ void *user_data)
+{
+ size_t i;
+
+ if (xdg_dirs == NULL)
+ xdg_init_dirs ();
+
+ for (i = 0; xdg_dirs[i] != NULL; i++)
+ {
+ if ((func) (xdg_dirs[i], user_data))
+ return;
+ }
+}
+
+/* Allows the calling code to override the directories used by xdgmime, without
+ * having to change environment variables in a running process (which is not
+ * thread safe). This is intended to be used by tests. The changes will be
+ * picked up by xdg_mime_init() next time public API is called.
+ *
+ * This will set @xdg_dirs. Directories in @dirs must be complete, including
+ * the conventional `/mime` subdirectory. This is to allow tests to override
+ * them without the need to create a subdirectory. */
+void
+xdg_mime_set_dirs (const char * const *dirs)
+{
+ size_t i;
+
+ for (i = 0; xdg_dirs != NULL && xdg_dirs[i] != NULL; i++)
+ free (xdg_dirs[i]);
+ free (xdg_dirs);
+ xdg_dirs = NULL;
+
+ if (dirs != NULL)
+ {
+ for (i = 0; dirs[i] != NULL; i++);
+ xdg_dirs = calloc (i + 1 /* NULL terminator */, sizeof (char*));
+ for (i = 0; dirs[i] != NULL; i++)
+ xdg_dirs[i] = strdup (dirs[i]);
+ xdg_dirs[i] = NULL;
+ }
+
+ need_reread = TRUE;
}
/* Checks file_path to make sure it has the same mtime as last time it was
@@ -354,8 +417,8 @@ xdg_check_dir (const char *directory,
assert (directory != NULL);
/* Check the mime.cache file */
- file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+ file_name = malloc (strlen (directory) + strlen ("/mime.cache") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/mime.cache");
invalid = xdg_check_file (file_name, &exists);
free (file_name);
if (invalid)
@@ -369,8 +432,8 @@ xdg_check_dir (const char *directory,
}
/* Check the globs file */
- file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+ file_name = malloc (strlen (directory) + strlen ("/globs") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/globs");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)
@@ -380,8 +443,8 @@ xdg_check_dir (const char *directory,
}
/* Check the magic file */
- file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
- strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+ file_name = malloc (strlen (directory) + strlen ("/magic") + 1);
+ strcpy (file_name, directory); strcat (file_name, "/magic");
invalid = xdg_check_file (file_name, NULL);
free (file_name);
if (invalid)
diff --git a/src/xdgmime.h b/src/xdgmime.h
index 6a34edf..7b3312c 100644
--- a/src/xdgmime.h
+++ b/src/xdgmime.h
@@ -119,6 +119,8 @@ int xdg_mime_register_reload_callback (XdgMimeCallback callback,
XdgMimeDestroy destroy);
void xdg_mime_remove_callback (int callback_id);
+void xdg_mime_set_dirs (const char * const *dirs);
+
/* Private versions of functions that don't call xdg_mime_init () */
int _xdg_mime_mime_type_equal (const char *mime_a,
const char *mime_b);