[glib] W32: Support XDG_* environment variables
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] W32: Support XDG_* environment variables
- Date: Mon, 14 Aug 2017 14:45:23 +0000 (UTC)
commit 788705633ede3a82f7ca0e1014dc8e6f7a02b349
Author: Руслан Ижбулатов <lrn1986 gmail com>
Date: Thu May 12 08:49:51 2016 +0000
W32: Support XDG_* environment variables
Try to get XDG_* environment variables and, if they are available, use their
contents to initialize various directories the same way this happens on *nix.
When these variables are not available, fall back to the W32-specific APIs for
getting directories.
https://bugzilla.gnome.org/show_bug.cgi?id=766358
glib/gutils.c | 190 +++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 125 insertions(+), 65 deletions(-)
---
diff --git a/glib/gutils.c b/glib/gutils.c
index 099bba5..eb44f17 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -63,6 +63,7 @@
#include "gstrfuncs.h"
#include "garray.h"
#include "glibintl.h"
+#include "gstdio.h"
#ifdef G_PLATFORM_WIN32
#include "gconvert.h"
@@ -1151,10 +1152,12 @@ g_set_application_name (const gchar *application_name)
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
* In this case the directory retrieved will be `XDG_DATA_HOME`.
*
- * On Windows this is the folder to use for local (as opposed to
- * roaming) application data. See documentation for
- * CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
- * what g_get_user_config_dir() returns.
+ * On Windows it follows XDG Base Directory Specification if `XDG_DATA_HOME`
+ * is defined. If `XDG_DATA_HOME` is undefined, the folder to use for local (as
+ * opposed to roaming) application data is used instead. See the
+ * [documentation for
`CSIDL_LOCAL_APPDATA`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494%28v=vs.85%29.aspx#csidl_local_appdata).
+ * Note that in this case on Windows it will be the same
+ * as what g_get_user_config_dir() returns.
*
* Returns: (type filename): a string owned by GLib that must not be modified
* or freed.
@@ -1163,19 +1166,19 @@ g_set_application_name (const gchar *application_name)
const gchar *
g_get_user_data_dir (void)
{
- gchar *data_dir;
+ gchar *data_dir = NULL;
G_LOCK (g_utils_global);
if (!g_user_data_dir)
{
-#ifdef G_OS_WIN32
- data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
-#else
- data_dir = (gchar *) g_getenv ("XDG_DATA_HOME");
+ const gchar *data_dir_env = g_getenv ("XDG_DATA_HOME");
- if (data_dir && data_dir[0])
- data_dir = g_strdup (data_dir);
+ if (data_dir_env && data_dir_env[0])
+ data_dir = g_strdup (data_dir_env);
+#ifdef G_OS_WIN32
+ else
+ data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
#endif
if (!data_dir || !data_dir[0])
{
@@ -1200,17 +1203,17 @@ g_get_user_data_dir (void)
static void
g_init_user_config_dir (void)
{
- gchar *config_dir;
+ gchar *config_dir = NULL;
if (!g_user_config_dir)
{
-#ifdef G_OS_WIN32
- config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
-#else
- config_dir = (gchar *) g_getenv ("XDG_CONFIG_HOME");
+ const gchar *config_dir_env = g_getenv ("XDG_CONFIG_HOME");
- if (config_dir && config_dir[0])
- config_dir = g_strdup (config_dir);
+ if (config_dir_env && config_dir_env[0])
+ config_dir = g_strdup (config_dir_env);
+#ifdef G_OS_WIN32
+ else
+ config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
#endif
if (!config_dir || !config_dir[0])
{
@@ -1237,10 +1240,12 @@ g_init_user_config_dir (void)
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
* In this case the directory retrieved will be `XDG_CONFIG_HOME`.
*
- * On Windows this is the folder to use for local (as opposed to
- * roaming) application data. See documentation for
- * CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
- * what g_get_user_data_dir() returns.
+ * On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_HOME` is defined.
+ * If `XDG_CONFIG_HOME` is undefined, the folder to use for local (as opposed
+ * to roaming) application data is used instead. See the
+ * [documentation for
`CSIDL_LOCAL_APPDATA`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494%28v=vs.85%29.aspx#csidl_local_appdata).
+ * Note that in this case on Windows it will be the same
+ * as what g_get_user_data_dir() returns.
*
* Returns: (type filename): a string owned by GLib that must not be modified
* or freed.
@@ -1267,12 +1272,13 @@ g_get_user_config_dir (void)
* 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_CACHE_HOME.
+ * In this case the directory retrieved will be `XDG_CACHE_HOME`.
*
- * On Windows is the directory that serves as a common repository for
- * temporary Internet files. A typical path is
- * C:\Documents and Settings\username\Local Settings\Temporary Internet Files.
- * See documentation for CSIDL_INTERNET_CACHE.
+ * On Windows it follows XDG Base Directory Specification if `XDG_CACHE_HOME` is defined.
+ * If `XDG_CACHE_HOME` is undefined, the directory that serves as a common
+ * repository for temporary Internet files is used instead. A typical path is
+ * `C:\Documents and Settings\username\Local Settings\Temporary Internet Files`.
+ * See the [documentation for
`CSIDL_INTERNET_CACHE`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494%28v=vs.85%29.aspx#csidl_internet_cache).
*
* Returns: (type filename): a string owned by GLib that must not be modified
* or freed.
@@ -1281,19 +1287,19 @@ g_get_user_config_dir (void)
const gchar *
g_get_user_cache_dir (void)
{
- gchar *cache_dir;
+ gchar *cache_dir = NULL;
G_LOCK (g_utils_global);
if (!g_user_cache_dir)
{
-#ifdef G_OS_WIN32
- cache_dir = get_special_folder (CSIDL_INTERNET_CACHE); /* XXX correct? */
-#else
- cache_dir = (gchar *) g_getenv ("XDG_CACHE_HOME");
+ const gchar *cache_dir_env = g_getenv ("XDG_CACHE_HOME");
- if (cache_dir && cache_dir[0])
- cache_dir = g_strdup (cache_dir);
+ if (cache_dir_env && cache_dir_env[0])
+ cache_dir = g_strdup (cache_dir_env);
+#ifdef G_OS_WIN32
+ else
+ cache_dir = get_special_folder (CSIDL_INTERNET_CACHE);
#endif
if (!cache_dir || !cache_dir[0])
{
@@ -1320,7 +1326,7 @@ g_get_user_cache_dir (void)
* Returns a directory that is unique to the current user on the local
* system.
*
- * On UNIX platforms this is determined using the mechanisms described
+ * This is determined using the mechanisms described
* in the
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
* This is the directory
@@ -1328,11 +1334,6 @@ g_get_user_cache_dir (void)
* In the case that this variable is not set, we return the value of
* g_get_user_cache_dir(), after verifying that it exists.
*
- * On Windows this is the folder to use for local (as opposed to
- * roaming) application data. See documentation for
- * CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
- * what g_get_user_config_dir() returns.
- *
* Returns: (type filename): a string owned by GLib that must not be
* modified or freed.
*
@@ -1341,7 +1342,6 @@ g_get_user_cache_dir (void)
const gchar *
g_get_user_runtime_dir (void)
{
-#ifndef G_OS_WIN32
static const gchar *runtime_dir;
if (g_once_init_enter (&runtime_dir))
@@ -1365,7 +1365,7 @@ g_get_user_runtime_dir (void)
* exists this will work. If the user changed $XDG_CACHE_HOME
* then they can make sure that it exists...
*/
- (void) mkdir (dir, 0700);
+ (void) g_mkdir (dir, 0700);
}
g_assert (dir != NULL);
@@ -1374,9 +1374,6 @@ g_get_user_runtime_dir (void)
}
return runtime_dir;
-#else /* Windows */
- return g_get_user_cache_dir ();
-#endif
}
#ifdef HAVE_CARBON
@@ -1816,8 +1813,8 @@ get_module_share_dir (gconstpointer address)
return retval;
}
-const gchar * const *
-g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
+static const gchar * const *
+g_win32_get_system_data_dirs_for_module_real (void (*address_of_function)(void))
{
GArray *data_dirs;
HMODULE hmodule;
@@ -1913,6 +1910,54 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
return (const gchar * const *) retval;
}
+const gchar * const *
+g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
+{
+ gboolean should_call_g_get_system_data_dirs;
+
+ should_call_g_get_system_data_dirs = TRUE;
+ /* These checks are the same as the ones that g_get_system_data_dirs() does.
+ * Please keep them in sync.
+ */
+ G_LOCK (g_utils_global);
+
+ if (!g_system_data_dirs)
+ {
+ const gchar *data_dirs = g_getenv ("XDG_DATA_DIRS");
+
+ if (!data_dirs || !data_dirs[0])
+ should_call_g_get_system_data_dirs = FALSE;
+ }
+
+ G_UNLOCK (g_utils_global);
+
+ /* There is a subtle difference between g_win32_get_system_data_dirs_for_module (NULL),
+ * which is what GLib code can normally call,
+ * and g_win32_get_system_data_dirs_for_module (&_g_win32_get_system_data_dirs),
+ * which is what the inline function used by non-GLib code calls.
+ * The former gets prefix relative to currently-running executable,
+ * the latter - relative to the module that calls _g_win32_get_system_data_dirs()
+ * (disguised as g_get_system_data_dirs()), which could be an executable or
+ * a DLL that is located somewhere else.
+ * This is why that inline function in gutils.h exists, and why we can't just
+ * call g_get_system_data_dirs() from there - because we need to get the address
+ * local to the non-GLib caller-module.
+ */
+
+ /*
+ * g_get_system_data_dirs() will fall back to calling
+ * g_win32_get_system_data_dirs_for_module_real(NULL) if XDG_DATA_DIRS is NULL
+ * or an empty string. The checks above ensure that we do not call it in such
+ * cases and use the address_of_function that we've been given by the inline function.
+ * The reason we're calling g_get_system_data_dirs /at all/ is to give
+ * XDG_DATA_DIRS precedence (if it is set).
+ */
+ if (should_call_g_get_system_data_dirs)
+ return g_get_system_data_dirs ();
+
+ return g_win32_get_system_data_dirs_for_module_real (address_of_function);
+}
+
#endif
/**
@@ -1924,9 +1969,11 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
* 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 list of directories retrieved will be XDG_DATA_DIRS.
+ * In this case the list of directories retrieved will be `XDG_DATA_DIRS`.
*
- * On Windows the first elements in the list are the Application Data
+ * On Windows it follows XDG Base Directory Specification if `XDG_DATA_DIRS` is defined.
+ * If `XDG_DATA_DIRS` is undefined,
+ * the first elements in the list are the Application Data
* and Documents folders for All Users. (These can be determined only
* on Windows 2000 or later and are not present in the list on other
* Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
@@ -1959,19 +2006,25 @@ g_get_system_data_dirs (void)
{
gchar **data_dir_vector;
+ /* These checks are the same as the ones that g_win32_get_system_data_dirs_for_module()
+ * does. Please keep them in sync.
+ */
G_LOCK (g_utils_global);
if (!g_system_data_dirs)
{
-#ifdef G_OS_WIN32
- data_dir_vector = (gchar **) g_win32_get_system_data_dirs_for_module (NULL);
-#else
gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
+#ifndef G_OS_WIN32
if (!data_dirs || !data_dirs[0])
data_dirs = "/usr/local/share/:/usr/share/";
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+#else
+ if (!data_dirs || !data_dirs[0])
+ data_dir_vector = g_strdupv ((gchar **) g_win32_get_system_data_dirs_for_module_real (NULL));
+ else
+ data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
#endif
g_system_data_dirs = data_dir_vector;
@@ -1995,12 +2048,15 @@ g_get_system_data_dirs (void)
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
* In this case the list of directories retrieved will be `XDG_CONFIG_DIRS`.
*
- * On Windows is the directory that contains application data for all users.
- * A typical path is C:\Documents and Settings\All Users\Application Data.
- * This folder is used for application data that is not user specific.
- * For example, an application can store a spell-check dictionary, a database
- * of clip art, or a log file in the CSIDL_COMMON_APPDATA folder.
- * This information will not roam and is available to anyone using the computer.
+ * On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_DIRS` is defined.
+ * If `XDG_CONFIG_DIRS` is undefined, the directory that contains application
+ * data for all users is used instead. A typical path is
+ * `C:\Documents and Settings\All Users\Application Data`.
+ * This folder is used for application data
+ * that is not user specific. For example, an application can store
+ * a spell-check dictionary, a database of clip art, or a log file in the
+ * CSIDL_COMMON_APPDATA folder. This information will not roam and is available
+ * to anyone using the computer.
*
* Returns: (array zero-terminated=1) (element-type filename) (transfer none):
* a %NULL-terminated array of strings owned by GLib that must not be
@@ -2011,27 +2067,31 @@ g_get_system_data_dirs (void)
const gchar * const *
g_get_system_config_dirs (void)
{
- gchar *conf_dirs, **conf_dir_vector;
+ gchar **conf_dir_vector;
G_LOCK (g_utils_global);
if (!g_system_config_dirs)
{
+ const gchar *conf_dirs = g_getenv ("XDG_CONFIG_DIRS");
#ifdef G_OS_WIN32
- conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
if (conf_dirs)
{
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
- g_free (conf_dirs);
}
else
{
- /* Return empty list */
- conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
+ gchar *special_conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
+
+ if (special_conf_dirs)
+ conf_dir_vector = g_strsplit (special_conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
+ else
+ /* Return empty list */
+ conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
+
+ g_free (special_conf_dirs);
}
#else
- conf_dirs = (gchar *) g_getenv ("XDG_CONFIG_DIRS");
-
if (!conf_dirs || !conf_dirs[0])
conf_dirs = "/etc/xdg";
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]