[glib: 8/11] xdgmime: Add xdg_mime_set_dirs() method to override XDG envvars




commit fa6f45536d4d97912ad29cee400c8ecab61d22aa
Author: Philip Withnall <withnall endlessm com>
Date:   Thu Dec 13 16:24:07 2018 +0000

    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>

 gio/xdgmime/xdgmime.c | 190 +++++++++++++++++++++++++++++++++-----------------
 gio/xdgmime/xdgmime.h |   2 +
 2 files changed, 129 insertions(+), 63 deletions(-)
---
diff --git a/gio/xdgmime/xdgmime.c b/gio/xdgmime/xdgmime.c
index 7575f5198..338211818 100644
--- a/gio/xdgmime/xdgmime.c
+++ b/gio/xdgmime/xdgmime.c
@@ -60,6 +60,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;
 
@@ -143,8 +145,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);
@@ -163,8 +165,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);
@@ -173,8 +175,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);
@@ -186,8 +188,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);
@@ -198,69 +200,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')
@@ -268,33 +282,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
@@ -348,8 +412,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)
@@ -363,8 +427,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)
@@ -374,8 +438,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/gio/xdgmime/xdgmime.h b/gio/xdgmime/xdgmime.h
index 38f6a2582..92dbc3422 100644
--- a/gio/xdgmime/xdgmime.h
+++ b/gio/xdgmime/xdgmime.h
@@ -129,6 +129,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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]