[glib: 1/2] utils: Add XDG_STATE_HOME support




commit 68eab1d99981a8cc6865239500fe4a84878d880c
Author: Sophie Herold <sophie hemio de>
Date:   Fri Dec 24 20:11:39 2021 +0000

    utils: Add XDG_STATE_HOME support

 docs/reference/glib/glib-sections.txt |  1 +
 glib/gtestutils.c                     |  5 ++-
 glib/gtestutils.h                     |  1 +
 glib/gutils.c                         | 67 +++++++++++++++++++++++++++++++++++
 glib/gutils.h                         |  2 ++
 glib/tests/utils.c                    |  9 +++++
 tests/testglib.c                      |  4 ++-
 7 files changed, 87 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index c563a0bcd..c8681fa2f 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2209,6 +2209,7 @@ g_get_real_name
 g_get_user_cache_dir
 g_get_user_data_dir
 g_get_user_config_dir
+g_get_user_state_dir
 g_get_user_runtime_dir
 GUserDirectory
 g_get_user_special_dir
diff --git a/glib/gtestutils.c b/glib/gtestutils.c
index 6273ab7e0..a061da799 100644
--- a/glib/gtestutils.c
+++ b/glib/gtestutils.c
@@ -1434,7 +1434,7 @@ test_do_isolate_dirs (GError **error)
 {
   gchar *subdir = NULL;
   gchar *home_dir = NULL, *cache_dir = NULL, *config_dir = NULL;
-  gchar *data_dir = NULL, *runtime_dir = NULL;
+  gchar *state_dir = NULL, *data_dir = NULL, *runtime_dir = NULL;
   gchar *config_dirs[3];
   gchar *data_dirs[3];
 
@@ -1471,6 +1471,7 @@ test_do_isolate_dirs (GError **error)
   cache_dir = g_build_filename (subdir, "cache", NULL);
   config_dir = g_build_filename (subdir, "config", NULL);
   data_dir = g_build_filename (subdir, "data", NULL);
+  state_dir = g_build_filename (subdir, "state", NULL);
 
   config_dirs[0] = g_build_filename (subdir, "system-config1", NULL);
   config_dirs[1] = g_build_filename (subdir, "system-config2", NULL);
@@ -1488,10 +1489,12 @@ test_do_isolate_dirs (GError **error)
                    "XDG_CONFIG_HOME", config_dir,
                    "XDG_DATA_DIRS", data_dirs,
                    "XDG_DATA_HOME", data_dir,
+                   "XDG_STATE_HOME", state_dir,
                    "XDG_RUNTIME_DIR", runtime_dir,
                    NULL);
 
   g_free (runtime_dir);
+  g_free (state_dir);
   g_free (data_dir);
   g_free (config_dir);
   g_free (cache_dir);
diff --git a/glib/gtestutils.h b/glib/gtestutils.h
index f5202ac44..7dee4822d 100644
--- a/glib/gtestutils.h
+++ b/glib/gtestutils.h
@@ -275,6 +275,7 @@ void    g_test_init                     (int            *argc,
  *  - g_get_user_config_dir()
  *  - g_get_system_data_dirs()
  *  - g_get_user_data_dir()
+ *  - g_get_user_state_dir()
  *  - g_get_user_runtime_dir()
  *
  * The subdirectories may not be created by the test harness; as with normal
diff --git a/glib/gutils.c b/glib/gutils.c
index 87f10f69f..6652d0ba0 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -549,6 +549,7 @@ static  gchar   *g_user_data_dir = NULL;
 static  gchar  **g_system_data_dirs = NULL;
 static  gchar   *g_user_cache_dir = NULL;
 static  gchar   *g_user_config_dir = NULL;
+static  gchar   *g_user_state_dir = NULL;
 static  gchar   *g_user_runtime_dir = NULL;
 static  gchar  **g_system_config_dirs = NULL;
 static  gchar  **g_user_special_dirs = NULL;
@@ -1770,6 +1771,8 @@ g_set_user_dirs (const gchar *first_dir_type,
         set_strv_if_different (&g_system_data_dirs, dir_type, dir_value);
       else if (g_str_equal (dir_type, "XDG_DATA_HOME"))
         set_str_if_different (&g_user_data_dir, dir_type, dir_value);
+      else if (g_str_equal (dir_type, "XDG_STATE_HOME"))
+        set_str_if_different (&g_user_state_dir, dir_type, dir_value);
       else if (g_str_equal (dir_type, "XDG_RUNTIME_DIR"))
         set_str_if_different (&g_user_runtime_dir, dir_type, dir_value);
       else
@@ -1970,6 +1973,70 @@ g_get_user_cache_dir (void)
   return user_cache_dir;
 }
 
+static gchar *
+g_build_user_state_dir (void)
+{
+  gchar *state_dir = NULL;
+  const gchar *state_dir_env = g_getenv ("XDG_STATE_HOME");
+
+  if (state_dir_env && state_dir_env[0])
+    state_dir = g_strdup (state_dir_env);
+#ifdef G_OS_WIN32
+  else
+    state_dir = get_special_folder (&FOLDERID_LocalAppData);
+#endif
+  if (!state_dir || !state_dir[0])
+    {
+      gchar *home_dir = g_build_home_dir ();
+      state_dir = g_build_filename (home_dir, ".local/state", NULL);
+      g_free (home_dir);
+    }
+
+  return g_steal_pointer (&state_dir);
+}
+
+/**
+ * g_get_user_state_dir:
+ *
+ * Returns a base directory in which to store state files specific to
+ * particular user.
+ *
+ * On UNIX platforms this is determined using the mechanisms described
+ * in the
+ * [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
+ * In this case the directory retrieved will be `XDG_STATE_HOME`.
+ *
+ * On Windows it follows XDG Base Directory Specification if `XDG_STATE_HOME` is defined.
+ * If `XDG_STATE_HOME` is undefined, the folder to use for local (as opposed
+ * to roaming) application data is used instead. See the
+ * [documentation for 
`FOLDERID_LocalAppData`](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
+ * Note that in this case on Windows it will be the same
+ * as what g_get_user_data_dir() returns.
+ *
+ * The return value is cached and modifying it at runtime is not supported, as
+ * it’s not thread-safe to modify environment variables at runtime.
+ *
+ * Returns: (type filename) (transfer none): a string owned by GLib that
+ *   must not be modified or freed.
+ *
+ * Since: 2.72
+ **/
+const gchar *
+g_get_user_state_dir (void)
+{
+  const gchar *user_state_dir;
+
+  G_LOCK (g_utils_global);
+
+  if (g_user_state_dir == NULL)
+    g_user_state_dir = g_build_user_state_dir ();
+  user_state_dir = g_user_state_dir;
+
+  G_UNLOCK (g_utils_global);
+
+  return user_state_dir;
+}
+
 static gchar *
 g_build_user_runtime_dir (void)
 {
diff --git a/glib/gutils.h b/glib/gutils.h
index f8a6049ff..08c187040 100644
--- a/glib/gutils.h
+++ b/glib/gutils.h
@@ -197,6 +197,8 @@ GLIB_AVAILABLE_IN_ALL
 const gchar *         g_get_user_config_dir    (void);
 GLIB_AVAILABLE_IN_ALL
 const gchar *         g_get_user_cache_dir     (void);
+GLIB_AVAILABLE_IN_2_72
+const gchar *         g_get_user_state_dir     (void);
 GLIB_AVAILABLE_IN_ALL
 const gchar * const * g_get_system_data_dirs   (void);
 
diff --git a/glib/tests/utils.c b/glib/tests/utils.c
index 6068cd9be..643978149 100644
--- a/glib/tests/utils.c
+++ b/glib/tests/utils.c
@@ -688,6 +688,15 @@ test_xdg_dirs (void)
   g_assert_cmpstr (dir, ==, xdg);
   g_free (xdg);
 
+  xdg = g_strdup (g_getenv ("XDG_STATE_HOME"));
+  if (!xdg)
+    xdg = g_build_filename (g_get_home_dir (), ".local/state", NULL);
+
+  dir = g_get_user_state_dir ();
+
+  g_assert_cmpstr (dir, ==, xdg);
+  g_free (xdg);
+
   xdg = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
   if (!xdg)
     xdg = g_strdup (g_get_user_cache_dir ());
diff --git a/tests/testglib.c b/tests/testglib.c
index 48cd74a2a..b692c4c31 100644
--- a/tests/testglib.c
+++ b/tests/testglib.c
@@ -877,7 +877,7 @@ static void
 test_info (void)
 {
   const gchar *un, *rn, *hn;
-  const gchar *tmpdir, *homedir, *userdatadir, *uconfdir, *ucachedir;
+  const gchar *tmpdir, *homedir, *userdatadir, *uconfdir, *ucachedir, *ustatedir;
   const gchar *uddesktop, *udddocs, *uddpubshare, *uruntimedir;
   gchar **sv, *cwd, *sdatadirs, *sconfdirs, *langnames;
   const gchar *charset;
@@ -917,6 +917,8 @@ test_info (void)
   g_assert (uconfdir != NULL);
   ucachedir = g_get_user_cache_dir ();
   g_assert (ucachedir != NULL);
+  ustatedir = g_get_user_state_dir ();
+  g_assert (ustatedir != NULL);
 
   uddesktop = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
   g_assert (uddesktop != NULL);


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