mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
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
This commit is contained in:
parent
f9fe9ea417
commit
788705633e
186
glib/gutils.c
186
glib/gutils.c
@ -63,6 +63,7 @@
|
|||||||
#include "gstrfuncs.h"
|
#include "gstrfuncs.h"
|
||||||
#include "garray.h"
|
#include "garray.h"
|
||||||
#include "glibintl.h"
|
#include "glibintl.h"
|
||||||
|
#include "gstdio.h"
|
||||||
|
|
||||||
#ifdef G_PLATFORM_WIN32
|
#ifdef G_PLATFORM_WIN32
|
||||||
#include "gconvert.h"
|
#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).
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
||||||
* In this case the directory retrieved will be `XDG_DATA_HOME`.
|
* In this case the directory retrieved will be `XDG_DATA_HOME`.
|
||||||
*
|
*
|
||||||
* On Windows this is the folder to use for local (as opposed to
|
* On Windows it follows XDG Base Directory Specification if `XDG_DATA_HOME`
|
||||||
* roaming) application data. See documentation for
|
* is defined. If `XDG_DATA_HOME` is undefined, the folder to use for local (as
|
||||||
* CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
|
* opposed to roaming) application data is used instead. See the
|
||||||
* what g_get_user_config_dir() returns.
|
* [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
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
||||||
* or freed.
|
* or freed.
|
||||||
@ -1163,19 +1166,19 @@ g_set_application_name (const gchar *application_name)
|
|||||||
const gchar *
|
const gchar *
|
||||||
g_get_user_data_dir (void)
|
g_get_user_data_dir (void)
|
||||||
{
|
{
|
||||||
gchar *data_dir;
|
gchar *data_dir = NULL;
|
||||||
|
|
||||||
G_LOCK (g_utils_global);
|
G_LOCK (g_utils_global);
|
||||||
|
|
||||||
if (!g_user_data_dir)
|
if (!g_user_data_dir)
|
||||||
{
|
{
|
||||||
#ifdef G_OS_WIN32
|
const gchar *data_dir_env = g_getenv ("XDG_DATA_HOME");
|
||||||
data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
|
||||||
#else
|
|
||||||
data_dir = (gchar *) g_getenv ("XDG_DATA_HOME");
|
|
||||||
|
|
||||||
if (data_dir && data_dir[0])
|
if (data_dir_env && data_dir_env[0])
|
||||||
data_dir = g_strdup (data_dir);
|
data_dir = g_strdup (data_dir_env);
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
else
|
||||||
|
data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
||||||
#endif
|
#endif
|
||||||
if (!data_dir || !data_dir[0])
|
if (!data_dir || !data_dir[0])
|
||||||
{
|
{
|
||||||
@ -1200,17 +1203,17 @@ g_get_user_data_dir (void)
|
|||||||
static void
|
static void
|
||||||
g_init_user_config_dir (void)
|
g_init_user_config_dir (void)
|
||||||
{
|
{
|
||||||
gchar *config_dir;
|
gchar *config_dir = NULL;
|
||||||
|
|
||||||
if (!g_user_config_dir)
|
if (!g_user_config_dir)
|
||||||
{
|
{
|
||||||
#ifdef G_OS_WIN32
|
const gchar *config_dir_env = g_getenv ("XDG_CONFIG_HOME");
|
||||||
config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
|
||||||
#else
|
|
||||||
config_dir = (gchar *) g_getenv ("XDG_CONFIG_HOME");
|
|
||||||
|
|
||||||
if (config_dir && config_dir[0])
|
if (config_dir_env && config_dir_env[0])
|
||||||
config_dir = g_strdup (config_dir);
|
config_dir = g_strdup (config_dir_env);
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
else
|
||||||
|
config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
||||||
#endif
|
#endif
|
||||||
if (!config_dir || !config_dir[0])
|
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).
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
||||||
* In this case the directory retrieved will be `XDG_CONFIG_HOME`.
|
* In this case the directory retrieved will be `XDG_CONFIG_HOME`.
|
||||||
*
|
*
|
||||||
* On Windows this is the folder to use for local (as opposed to
|
* On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_HOME` is defined.
|
||||||
* roaming) application data. See documentation for
|
* If `XDG_CONFIG_HOME` is undefined, the folder to use for local (as opposed
|
||||||
* CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
|
* to roaming) application data is used instead. See the
|
||||||
* what g_get_user_data_dir() returns.
|
* [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
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
||||||
* or freed.
|
* or freed.
|
||||||
@ -1267,12 +1272,13 @@ g_get_user_config_dir (void)
|
|||||||
* On UNIX platforms this is determined using the mechanisms described
|
* On UNIX platforms this is determined using the mechanisms described
|
||||||
* in the
|
* in the
|
||||||
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
* [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
|
* On Windows it follows XDG Base Directory Specification if `XDG_CACHE_HOME` is defined.
|
||||||
* temporary Internet files. A typical path is
|
* If `XDG_CACHE_HOME` is undefined, the directory that serves as a common
|
||||||
* C:\Documents and Settings\username\Local Settings\Temporary Internet Files.
|
* repository for temporary Internet files is used instead. A typical path is
|
||||||
* See documentation for CSIDL_INTERNET_CACHE.
|
* `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
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
||||||
* or freed.
|
* or freed.
|
||||||
@ -1281,19 +1287,19 @@ g_get_user_config_dir (void)
|
|||||||
const gchar *
|
const gchar *
|
||||||
g_get_user_cache_dir (void)
|
g_get_user_cache_dir (void)
|
||||||
{
|
{
|
||||||
gchar *cache_dir;
|
gchar *cache_dir = NULL;
|
||||||
|
|
||||||
G_LOCK (g_utils_global);
|
G_LOCK (g_utils_global);
|
||||||
|
|
||||||
if (!g_user_cache_dir)
|
if (!g_user_cache_dir)
|
||||||
{
|
{
|
||||||
#ifdef G_OS_WIN32
|
const gchar *cache_dir_env = g_getenv ("XDG_CACHE_HOME");
|
||||||
cache_dir = get_special_folder (CSIDL_INTERNET_CACHE); /* XXX correct? */
|
|
||||||
#else
|
|
||||||
cache_dir = (gchar *) g_getenv ("XDG_CACHE_HOME");
|
|
||||||
|
|
||||||
if (cache_dir && cache_dir[0])
|
if (cache_dir_env && cache_dir_env[0])
|
||||||
cache_dir = g_strdup (cache_dir);
|
cache_dir = g_strdup (cache_dir_env);
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
else
|
||||||
|
cache_dir = get_special_folder (CSIDL_INTERNET_CACHE);
|
||||||
#endif
|
#endif
|
||||||
if (!cache_dir || !cache_dir[0])
|
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
|
* Returns a directory that is unique to the current user on the local
|
||||||
* system.
|
* system.
|
||||||
*
|
*
|
||||||
* On UNIX platforms this is determined using the mechanisms described
|
* This is determined using the mechanisms described
|
||||||
* in the
|
* in the
|
||||||
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
||||||
* This is the directory
|
* 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
|
* In the case that this variable is not set, we return the value of
|
||||||
* g_get_user_cache_dir(), after verifying that it exists.
|
* 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
|
* Returns: (type filename): a string owned by GLib that must not be
|
||||||
* modified or freed.
|
* modified or freed.
|
||||||
*
|
*
|
||||||
@ -1341,7 +1342,6 @@ g_get_user_cache_dir (void)
|
|||||||
const gchar *
|
const gchar *
|
||||||
g_get_user_runtime_dir (void)
|
g_get_user_runtime_dir (void)
|
||||||
{
|
{
|
||||||
#ifndef G_OS_WIN32
|
|
||||||
static const gchar *runtime_dir;
|
static const gchar *runtime_dir;
|
||||||
|
|
||||||
if (g_once_init_enter (&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
|
* exists this will work. If the user changed $XDG_CACHE_HOME
|
||||||
* then they can make sure that it exists...
|
* then they can make sure that it exists...
|
||||||
*/
|
*/
|
||||||
(void) mkdir (dir, 0700);
|
(void) g_mkdir (dir, 0700);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_assert (dir != NULL);
|
g_assert (dir != NULL);
|
||||||
@ -1374,9 +1374,6 @@ g_get_user_runtime_dir (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return runtime_dir;
|
return runtime_dir;
|
||||||
#else /* Windows */
|
|
||||||
return g_get_user_cache_dir ();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CARBON
|
#ifdef HAVE_CARBON
|
||||||
@ -1816,8 +1813,8 @@ get_module_share_dir (gconstpointer address)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar * const *
|
static const gchar * const *
|
||||||
g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
|
g_win32_get_system_data_dirs_for_module_real (void (*address_of_function)(void))
|
||||||
{
|
{
|
||||||
GArray *data_dirs;
|
GArray *data_dirs;
|
||||||
HMODULE hmodule;
|
HMODULE hmodule;
|
||||||
@ -1913,6 +1910,54 @@ g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
|
|||||||
return (const gchar * const *) retval;
|
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
|
#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
|
* On UNIX platforms this is determined using the mechanisms described
|
||||||
* in the
|
* in the
|
||||||
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec)
|
* [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
|
* 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
|
* on Windows 2000 or later and are not present in the list on other
|
||||||
* Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
|
* Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
|
||||||
@ -1959,18 +2006,24 @@ g_get_system_data_dirs (void)
|
|||||||
{
|
{
|
||||||
gchar **data_dir_vector;
|
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);
|
G_LOCK (g_utils_global);
|
||||||
|
|
||||||
if (!g_system_data_dirs)
|
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");
|
gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
|
||||||
|
|
||||||
|
#ifndef G_OS_WIN32
|
||||||
if (!data_dirs || !data_dirs[0])
|
if (!data_dirs || !data_dirs[0])
|
||||||
data_dirs = "/usr/local/share/:/usr/share/";
|
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);
|
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1995,12 +2048,15 @@ g_get_system_data_dirs (void)
|
|||||||
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
||||||
* In this case the list of directories retrieved will be `XDG_CONFIG_DIRS`.
|
* 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.
|
* On Windows it follows XDG Base Directory Specification if `XDG_CONFIG_DIRS` is defined.
|
||||||
* A typical path is C:\Documents and Settings\All Users\Application Data.
|
* If `XDG_CONFIG_DIRS` is undefined, the directory that contains application
|
||||||
* This folder is used for application data that is not user specific.
|
* data for all users is used instead. A typical path is
|
||||||
* For example, an application can store a spell-check dictionary, a database
|
* `C:\Documents and Settings\All Users\Application Data`.
|
||||||
* of clip art, or a log file in the CSIDL_COMMON_APPDATA folder.
|
* This folder is used for application data
|
||||||
* This information will not roam and is available to anyone using the computer.
|
* 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):
|
* Returns: (array zero-terminated=1) (element-type filename) (transfer none):
|
||||||
* a %NULL-terminated array of strings owned by GLib that must not be
|
* 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 *
|
const gchar * const *
|
||||||
g_get_system_config_dirs (void)
|
g_get_system_config_dirs (void)
|
||||||
{
|
{
|
||||||
gchar *conf_dirs, **conf_dir_vector;
|
gchar **conf_dir_vector;
|
||||||
|
|
||||||
G_LOCK (g_utils_global);
|
G_LOCK (g_utils_global);
|
||||||
|
|
||||||
if (!g_system_config_dirs)
|
if (!g_system_config_dirs)
|
||||||
{
|
{
|
||||||
|
const gchar *conf_dirs = g_getenv ("XDG_CONFIG_DIRS");
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
|
|
||||||
if (conf_dirs)
|
if (conf_dirs)
|
||||||
{
|
{
|
||||||
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||||
g_free (conf_dirs);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
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 */
|
/* Return empty list */
|
||||||
conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
|
conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
|
||||||
|
|
||||||
|
g_free (special_conf_dirs);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
conf_dirs = (gchar *) g_getenv ("XDG_CONFIG_DIRS");
|
|
||||||
|
|
||||||
if (!conf_dirs || !conf_dirs[0])
|
if (!conf_dirs || !conf_dirs[0])
|
||||||
conf_dirs = "/etc/xdg";
|
conf_dirs = "/etc/xdg";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user