Commit b6f7f374 authored by Philip Withnall's avatar Philip Withnall

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's avatarPhilip Withnall <withnall@endlessm.com>
parent b4de2e32
......@@ -56,6 +56,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;
......@@ -139,8 +141,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);
......@@ -159,8 +161,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);
......@@ -169,8 +171,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);
......@@ -182,8 +184,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);
......@@ -194,69 +196,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')
......@@ -264,33 +278,83 @@ 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]);
if (xdg_dirs != NULL)
free (xdg_dirs[i]);
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
......@@ -344,8 +408,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)
......@@ -359,8 +423,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)
......@@ -370,8 +434,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)
......
......@@ -127,6 +127,8 @@ int xdg_mime_register_reload_callback (XdgMimeCallback callback,
void xdg_mime_remove_callback (int callback_id);
#endif
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment