diff options
Diffstat (limited to '')
-rw-r--r-- | libgimpbase/gimpenv.c | 1260 |
1 files changed, 1260 insertions, 0 deletions
diff --git a/libgimpbase/gimpenv.c b/libgimpbase/gimpenv.c new file mode 100644 index 0000000..d4040c8 --- /dev/null +++ b/libgimpbase/gimpenv.c @@ -0,0 +1,1260 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpenv.c + * Copyright (C) 1999 Tor Lillqvist <tml@iki.fi> + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef PLATFORM_OSX +#include <AppKit/AppKit.h> +#endif + +#include <gio/gio.h> +#include <glib/gstdio.h> + +#undef GIMP_DISABLE_DEPRECATED +#include "gimpbasetypes.h" + +#define __GIMP_ENV_C__ +#include "gimpenv.h" +#include "gimpversion.h" +#include "gimpreloc.h" + +#ifdef G_OS_WIN32 +#define STRICT +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <io.h> +#ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +#endif +#ifndef S_IWGRP +#define S_IWGRP (_S_IWRITE>>3) +#define S_IWOTH (_S_IWRITE>>6) +#endif +#ifndef S_ISDIR +# define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask)) +# define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR) +#endif +#define uid_t gint +#define gid_t gint +#define geteuid() 0 +#define getegid() 0 + +#include <shlobj.h> + +/* Constant available since Shell32.dll 4.72 */ +#ifndef CSIDL_APPDATA +#define CSIDL_APPDATA 0x001a +#endif + +#endif + + +/** + * SECTION: gimpenv + * @title: gimpenv + * @short_description: Functions to access the GIMP environment. + * + * A set of functions to find the locations of GIMP's data directories + * and configuration files. + **/ + + +static gchar * gimp_env_get_dir (const gchar *gimp_env_name, + const gchar *compile_time_dir, + const gchar *relative_subdir); +#ifdef G_OS_WIN32 +static gchar * get_special_folder (gint csidl); +#endif + + +const guint gimp_major_version = GIMP_MAJOR_VERSION; +const guint gimp_minor_version = GIMP_MINOR_VERSION; +const guint gimp_micro_version = GIMP_MICRO_VERSION; + + +/** + * gimp_env_init: + * @plug_in: must be %TRUE if this function is called from a plug-in + * + * You don't need to care about this function. It is being called for + * you automatically (by means of the MAIN() macro that every plug-in + * runs). Calling it again will cause a fatal error. + * + * Since: 2.4 + */ +void +gimp_env_init (gboolean plug_in) +{ + static gboolean gimp_env_initialized = FALSE; + const gchar *data_home = g_get_user_data_dir (); + + if (gimp_env_initialized) + g_error ("gimp_env_init() must only be called once!"); + + gimp_env_initialized = TRUE; + +#ifndef G_OS_WIN32 + if (plug_in) + { + _gimp_reloc_init_lib (NULL); + } + else if (_gimp_reloc_init (NULL)) + { + /* Set $LD_LIBRARY_PATH to ensure that plugins can be loaded. */ + + const gchar *ldpath = g_getenv ("LD_LIBRARY_PATH"); + gchar *libdir = g_build_filename (gimp_installation_directory (), + "lib", + NULL); + + if (ldpath && *ldpath) + { + gchar *tmp = g_strconcat (libdir, ":", ldpath, NULL); + + g_setenv ("LD_LIBRARY_PATH", tmp, TRUE); + + g_free (tmp); + } + else + { + g_setenv ("LD_LIBRARY_PATH", libdir, TRUE); + } + + g_free (libdir); + } +#endif + + /* The user data directory (XDG_DATA_HOME on Unix) is used to store + * various data, like crash logs (win32) or recently used file history + * (by GTK+). Yet it may be absent, in particular on non-Linux + * platforms. Make sure it exists. + */ + if (! g_file_test (data_home, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir_with_parents (data_home, S_IRUSR | S_IWUSR | S_IXUSR) != 0) + { + g_warning ("Failed to create the data directory '%s': %s", + data_home, g_strerror (errno)); + } + } +} + +/** + * gimp_directory: + * + * Returns the user-specific GIMP settings directory. If the + * environment variable GIMP2_DIRECTORY exists, it is used. If it is + * an absolute path, it is used as is. If it is a relative path, it + * is taken to be a subdirectory of the home directory. If it is a + * relative path, and no home directory can be determined, it is taken + * to be a subdirectory of gimp_data_directory(). + * + * The usual case is that no GIMP2_DIRECTORY environment variable + * exists, and then we use the GIMPDIR subdirectory of the local + * configuration directory: + * + * - UNIX: $XDG_CONFIG_HOME (defaults to $HOME/.config/) + * + * - Windows: CSIDL_APPDATA + * + * - OSX (UNIX exception): the Application Support Directory. + * + * If neither the configuration nor home directory exist, + * g_get_user_config_dir() will return {tmp}/{user_name}/.config/ where + * the temporary directory {tmp} and the {user_name} are determined + * according to platform rules. + * + * In any case, we always return some non-empty string, whether it + * corresponds to an existing directory or not. + * + * In config files such as gimprc, the string ${gimp_dir} expands to + * this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8 (on Windows it is always + * UTF-8.) + * + * Returns: The user-specific GIMP settings directory. + **/ +const gchar * +gimp_directory (void) +{ + static gchar *gimp_dir = NULL; + static gchar *last_env_gimp_dir = NULL; + + const gchar *env_gimp_dir; + + env_gimp_dir = g_getenv ("GIMP2_DIRECTORY"); + + if (gimp_dir) + { + gboolean gimp2_directory_changed = FALSE; + + /* We have constructed the gimp_dir already. We can return + * gimp_dir unless some parameter gimp_dir depends on has + * changed. For now we just check for changes to GIMP2_DIRECTORY + */ + gimp2_directory_changed = + (env_gimp_dir == NULL && + last_env_gimp_dir != NULL) || + (env_gimp_dir != NULL && + last_env_gimp_dir == NULL) || + (env_gimp_dir != NULL && + last_env_gimp_dir != NULL && + strcmp (env_gimp_dir, last_env_gimp_dir) != 0); + + if (! gimp2_directory_changed) + { + return gimp_dir; + } + else + { + /* Free the old gimp_dir and go on to update it */ + g_free (gimp_dir); + gimp_dir = NULL; + } + } + + /* Remember the GIMP2_DIRECTORY to next invocation so we can check + * if it changes + */ + g_free (last_env_gimp_dir); + last_env_gimp_dir = g_strdup (env_gimp_dir); + + if (env_gimp_dir) + { + if (g_path_is_absolute (env_gimp_dir)) + { + gimp_dir = g_strdup (env_gimp_dir); + } + else + { + const gchar *home_dir = g_get_home_dir (); + + if (home_dir) + gimp_dir = g_build_filename (home_dir, env_gimp_dir, NULL); + else + gimp_dir = g_build_filename (gimp_data_directory (), env_gimp_dir, NULL); + } + } + else if (g_path_is_absolute (GIMPDIR)) + { + gimp_dir = g_strdup (GIMPDIR); + } + else + { +#ifdef PLATFORM_OSX + + NSAutoreleasePool *pool; + NSArray *path; + NSString *library_dir; + + pool = [[NSAutoreleasePool alloc] init]; + + path = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory, + NSUserDomainMask, YES); + library_dir = [path objectAtIndex:0]; + + gimp_dir = g_build_filename ([library_dir UTF8String], + GIMPDIR, GIMP_USER_VERSION, NULL); + + [pool drain]; + +#elif defined G_OS_WIN32 + + gchar *conf_dir = get_special_folder (CSIDL_APPDATA); + + gimp_dir = g_build_filename (conf_dir, + GIMPDIR, GIMP_USER_VERSION, NULL); + g_free(conf_dir); + +#else /* UNIX */ + + /* g_get_user_config_dir () always returns a path as a non-null + * and non-empty string + */ + gimp_dir = g_build_filename (g_get_user_config_dir (), + GIMPDIR, GIMP_USER_VERSION, NULL); + +#endif /* PLATFORM_OSX */ + } + + return gimp_dir; +} + +#ifdef G_OS_WIN32 + +/* Taken from glib 2.35 code. */ +static gchar * +get_special_folder (int csidl) +{ + wchar_t path[MAX_PATH+1]; + HRESULT hr; + LPITEMIDLIST pidl = NULL; + BOOL b; + gchar *retval = NULL; + + hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl); + if (hr == S_OK) + { + b = SHGetPathFromIDListW (pidl, path); + if (b) + retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL); + CoTaskMemFree (pidl); + } + + return retval; +} + +static HMODULE libgimpbase_dll = NULL; + +/* Minimal DllMain that just stores the handle to this DLL */ + +BOOL WINAPI /* Avoid silly "no previous prototype" gcc warning */ +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + libgimpbase_dll = hinstDLL; + break; + } + + return TRUE; +} + +#endif + +/** + * gimp_installation_directory: + * + * Returns the top installation directory of GIMP. On Unix the + * compile-time defined installation prefix is used. On Windows, the + * installation directory as deduced from the executable's full + * filename is used. On OSX we ask [NSBundle mainBundle] for the + * resource path to check if GIMP is part of a relocatable bundle. + * + * In config files such as gimprc, the string ${gimp_installation_dir} + * expands to this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.) + * + * Since: 2.8 + * + * Returns: The toplevel installation directory of GIMP. + **/ +const gchar * +gimp_installation_directory (void) +{ + static gchar *toplevel = NULL; + + if (toplevel) + return toplevel; + +#ifdef G_OS_WIN32 + + toplevel = g_win32_get_package_installation_directory_of_module (libgimpbase_dll); + if (! toplevel) + g_error ("g_win32_get_package_installation_directory_of_module() failed"); + +#elif PLATFORM_OSX + + { + NSAutoreleasePool *pool; + NSString *resource_path; + gchar *basename; + gchar *dirname; + + pool = [[NSAutoreleasePool alloc] init]; + + resource_path = [[NSBundle mainBundle] resourcePath]; + + basename = g_path_get_basename ([resource_path UTF8String]); + dirname = g_path_get_dirname ([resource_path UTF8String]); + + if (! strcmp (basename, ".libs")) + { + /* we are running from the source dir, do normal unix things */ + + toplevel = _gimp_reloc_find_prefix (PREFIX); + } + else if (! strcmp (basename, "bin")) + { + /* we are running the main app, but not from a bundle, the resource + * path is the directory which contains the executable + */ + + toplevel = g_strdup (dirname); + } + else if (! strcmp (basename, "plug-ins")) + { + /* same for plug-ins, go three levels up from prefix/lib/gimp/x.y */ + + gchar *tmp = g_path_get_dirname (dirname); + gchar *tmp2 = g_path_get_dirname (tmp); + + toplevel = g_path_get_dirname (tmp2); + + g_free (tmp); + g_free (tmp2); + } + else + { + /* if none of the above match, we assume that we are really in a bundle */ + + toplevel = g_strdup ([resource_path UTF8String]); + } + + g_free (basename); + g_free (dirname); + + [pool drain]; + } + +#else + + toplevel = _gimp_reloc_find_prefix (PREFIX); + +#endif + + return toplevel; +} + +/** + * gimp_data_directory: + * + * Returns the default top directory for GIMP data. If the environment + * variable GIMP2_DATADIR exists, that is used. It should be an + * absolute pathname. Otherwise, on Unix the compile-time defined + * directory is used. On Windows, the installation directory as + * deduced from the executable's full filename is used. + * + * Note that the actual directories used for GIMP data files can be + * overridden by the user in the preferences dialog. + * + * In config files such as gimprc, the string ${gimp_data_dir} expands + * to this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.) + * + * Returns: The top directory for GIMP data. + **/ +const gchar * +gimp_data_directory (void) +{ + static gchar *gimp_data_dir = NULL; + + if (! gimp_data_dir) + { + gchar *tmp = g_build_filename ("share", + GIMP_PACKAGE, + GIMP_DATA_VERSION, + NULL); + + gimp_data_dir = gimp_env_get_dir ("GIMP2_DATADIR", GIMPDATADIR, tmp); + g_free (tmp); + } + + return gimp_data_dir; +} + +/** + * gimp_locale_directory: + * + * Returns the top directory for GIMP locale files. If the environment + * variable GIMP2_LOCALEDIR exists, that is used. It should be an + * absolute pathname. Otherwise, on Unix the compile-time defined + * directory is used. On Windows, the installation directory as deduced + * from the executable's full filename is used. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * the C library, which isn't necessarily UTF-8. (On Windows, unlike + * the other similar functions here, the return value from this + * function is in the system codepage, never in UTF-8. It can thus be + * passed directly to the bindtextdomain() function from libintl which + * does not handle UTF-8.) + * + * Returns: The top directory for GIMP locale files. + */ +const gchar * +gimp_locale_directory (void) +{ + static gchar *gimp_locale_dir = NULL; + + if (! gimp_locale_dir) + { + gchar *tmp = g_build_filename ("share", + "locale", + NULL); + + gimp_locale_dir = gimp_env_get_dir ("GIMP2_LOCALEDIR", LOCALEDIR, tmp); + g_free (tmp); + +#ifdef G_OS_WIN32 + /* FIXME: g_win32_locale_filename_from_utf8() can actually return + * NULL (we had actual cases of this). Not sure exactly what + * gimp_locale_directory() should do when this happens. Anyway + * that's really broken, and something should be done some day + * about this! + */ + tmp = g_win32_locale_filename_from_utf8 (gimp_locale_dir); + g_free (gimp_locale_dir); + gimp_locale_dir = tmp; +#endif + } + + return gimp_locale_dir; +} + +/** + * gimp_sysconf_directory: + * + * Returns the top directory for GIMP config files. If the environment + * variable GIMP2_SYSCONFDIR exists, that is used. It should be an + * absolute pathname. Otherwise, on Unix the compile-time defined + * directory is used. On Windows, the installation directory as deduced + * from the executable's full filename is used. + * + * In config files such as gimprc, the string ${gimp_sysconf_dir} + * expands to this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.). + * + * Returns: The top directory for GIMP config files. + **/ +const gchar * +gimp_sysconf_directory (void) +{ + static gchar *gimp_sysconf_dir = NULL; + + if (! gimp_sysconf_dir) + { + gchar *tmp = g_build_filename ("etc", + GIMP_PACKAGE, + GIMP_SYSCONF_VERSION, + NULL); + + gimp_sysconf_dir = gimp_env_get_dir ("GIMP2_SYSCONFDIR", GIMPSYSCONFDIR, tmp); + g_free (tmp); + } + + return gimp_sysconf_dir; +} + +/** + * gimp_plug_in_directory: + * + * Returns the default top directory for GIMP plug-ins and modules. If + * the environment variable GIMP2_PLUGINDIR exists, that is used. It + * should be an absolute pathname. Otherwise, on Unix the compile-time + * defined directory is used. On Windows, the installation directory + * as deduced from the executable's full filename is used. + * + * Note that the actual directories used for GIMP plug-ins and modules + * can be overridden by the user in the preferences dialog. + * + * In config files such as gimprc, the string ${gimp_plug_in_dir} + * expands to this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.) + * + * Returns: The top directory for GIMP plug_ins and modules. + **/ +const gchar * +gimp_plug_in_directory (void) +{ + static gchar *gimp_plug_in_dir = NULL; + + if (! gimp_plug_in_dir) + { + gchar *tmp = g_build_filename ("lib", + GIMP_PACKAGE, + GIMP_PLUGIN_VERSION, + NULL); + + gimp_plug_in_dir = gimp_env_get_dir ("GIMP2_PLUGINDIR", PLUGINDIR, tmp); + g_free (tmp); + } + + return gimp_plug_in_dir; +} + +/** + * gimp_cache_directory: + * + * Returns the default top directory for GIMP cached files. If the + * environment variable GIMP2_CACHEDIR exists, that is used. It + * should be an absolute pathname. Otherwise, a subdirectory of the + * directory returned by g_get_user_cache_dir() is used. + * + * Note that the actual directories used for GIMP caches files can + * be overridden by the user in the preferences dialog. + * + * In config files such as gimprc, the string ${gimp_cache_dir} + * expands to this directory. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.). + * + * Since: 2.10.10 + * + * Returns: The default top directory for GIMP cached files. + **/ +const gchar * +gimp_cache_directory (void) +{ + static gchar *gimp_cache_dir = NULL; + + if (! gimp_cache_dir) + { + gchar *tmp = g_build_filename (g_get_user_cache_dir (), + GIMP_PACKAGE, + GIMP_USER_VERSION, + NULL); + + gimp_cache_dir = gimp_env_get_dir ("GIMP2_CACHEDIR", NULL, tmp); + g_free (tmp); + } + + return gimp_cache_dir; +} + +/** + * gimp_temp_directory: + * + * Returns the default top directory for GIMP temporary files. If the + * environment variable GIMP2_TEMPDIR exists, that is used. It + * should be an absolute pathname. Otherwise, a subdirectory of the + * directory returned by g_get_tmp_dir() is used. + * + * In config files such as gimprc, the string ${gimp_temp_dir} expands + * to this directory. + * + * Note that the actual directories used for GIMP temporary files can + * be overridden by the user in the preferences dialog. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.). + * + * Since: 2.10.10 + * + * Returns: The default top directory for GIMP temporary files. + **/ +const gchar * +gimp_temp_directory (void) +{ + static gchar *gimp_temp_dir = NULL; + + if (! gimp_temp_dir) + { + gchar *tmp = g_build_filename (g_get_tmp_dir (), + GIMP_PACKAGE, + GIMP_USER_VERSION, + NULL); + + gimp_temp_dir = gimp_env_get_dir ("GIMP2_TEMPDIR", NULL, tmp); + g_free (tmp); + } + + return gimp_temp_dir; +} + +static GFile * +gimp_child_file (const gchar *parent, + const gchar *element, + va_list args) +{ + GFile *file = g_file_new_for_path (parent); + + while (element) + { + GFile *child = g_file_get_child (file, element); + + g_object_unref (file); + file = child; + + element = va_arg (args, const gchar *); + } + + return file; +} + +/** + * gimp_directory_file: + * @first_element: the first element of a path to a file in the + * user's GIMP directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the user's GIMP directory, or the data + * directory itself if @first_element is %NULL. + * + * See also: gimp_directory(). + * + * Since: 2.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_installation_directory_file: + * @first_element: the first element of a path to a file in the + * top installation directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the installation directory, or the installation + * directory itself if @first_element is %NULL. + * + * See also: gimp_installation_directory(). + * + * Since: 2.10.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_installation_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_installation_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_data_directory_file: + * @first_element: the first element of a path to a file in the + * data directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the data directory, or the data directory + * itself if @first_element is %NULL. + * + * See also: gimp_data_directory(). + * + * Since: 2.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_data_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_data_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_locale_directory_file: + * @first_element: the first element of a path to a file in the + * locale directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the locale directory, or the locale directory + * itself if @first_element is %NULL. + * + * See also: gimp_locale_directory(). + * + * Since: 2.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_locale_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_locale_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_sysconf_directory_file: + * @first_element: the first element of a path to a file in the + * sysconf directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the sysconf directory, or the sysconf directory + * itself if @first_element is %NULL. + * + * See also: gimp_sysconf_directory(). + * + * Since: 2.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_sysconf_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_sysconf_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_plug_in_directory_file: + * @first_element: the first element of a path to a file in the + * plug-in directory, or %NULL. + * @...: a %NULL terminated list of the remaining elements of the path + * to the file. + * + * Returns a #GFile in the plug-in directory, or the plug-in directory + * itself if @first_element is %NULL. + * + * See also: gimp_plug_in_directory(). + * + * Since: 2.10 + * + * Returns: a new @GFile for the path, Free with g_object_unref(). + **/ +GFile * +gimp_plug_in_directory_file (const gchar *first_element, + ...) +{ + GFile *file; + va_list args; + + va_start (args, first_element); + file = gimp_child_file (gimp_plug_in_directory (), first_element, args); + va_end (args); + + return file; +} + +/** + * gimp_user_directory: + * @type: the type of user directory to retrieve + * + * This procedure is deprecated! Use g_get_user_special_dir() instead. + * + * Returns: The path to the specified user directory, or %NULL if the + * logical ID was not found. + * + * Since: 2.4 + **/ +const gchar * +gimp_user_directory (GimpUserDirectory type) +{ + return g_get_user_special_dir ((GUserDirectory) type); +} + +/** + * gimp_personal_rc_file: + * @basename: The basename of a rc_file. + * + * Returns the name of a file in the user-specific GIMP settings directory. + * + * The returned string is newly allocated and should be freed with + * g_free() after use. The returned string is in the encoding used for + * filenames by GLib, which isn't necessarily UTF-8. (On Windows it + * always is UTF-8.) + * + * Returns: The name of a file in the user-specific GIMP settings directory. + **/ +gchar * +gimp_personal_rc_file (const gchar *basename) +{ + return g_build_filename (gimp_directory (), basename, NULL); +} + +/** + * gimp_gtkrc: + * + * Returns the name of GIMP's application-specific gtkrc file. + * + * The returned string is owned by GIMP and must not be modified or + * freed. The returned string is in the encoding used for filenames by + * GLib, which isn't necessarily UTF-8. (On Windows it always is + * UTF-8.) + * + * Returns: The name of GIMP's application-specific gtkrc file. + **/ +const gchar * +gimp_gtkrc (void) +{ + static gchar *gimp_gtkrc_filename = NULL; + + if (! gimp_gtkrc_filename) + gimp_gtkrc_filename = g_build_filename (gimp_data_directory (), + "themes", "System", "gtkrc", + NULL); + + return gimp_gtkrc_filename; +} + +/** + * gimp_path_runtime_fix: + * @path: A pointer to a string (allocated with g_malloc) that is + * (or could be) a pathname. + * + * On Windows, this function checks if the string pointed to by @path + * starts with the compile-time prefix, and in that case, replaces the + * prefix with the run-time one. @path should be a pointer to a + * dynamically allocated (with g_malloc, g_strconcat, etc) string. If + * the replacement takes place, the original string is deallocated, + * and *@path is replaced with a pointer to a new string with the + * run-time prefix spliced in. + * + * On Linux, it does the same thing, but only if BinReloc support is enabled. + * On other Unices, it does nothing because those platforms don't have a + * way to find out where our binary is. + */ +static void +gimp_path_runtime_fix (gchar **path) +{ +#if defined (G_OS_WIN32) && defined (PREFIX) + gchar *p; + + /* Yes, I do mean forward slashes below */ + if (strncmp (*path, PREFIX "/", strlen (PREFIX "/")) == 0) + { + /* This is a compile-time entry. Replace the path with the + * real one on this machine. + */ + p = *path; + *path = g_strconcat (gimp_installation_directory (), + "\\", + *path + strlen (PREFIX "/"), + NULL); + g_free (p); + } + /* Replace forward slashes with backslashes, just for + * completeness */ + p = *path; + while ((p = strchr (p, '/')) != NULL) + { + *p = '\\'; + p++; + } +#elif defined (G_OS_WIN32) + /* without defineing PREFIX do something useful too */ + gchar *p = *path; + if (!g_path_is_absolute (p)) + { + *path = g_build_filename (gimp_installation_directory (), *path, NULL); + g_free (p); + } +#else + gchar *p; + + if (strncmp (*path, PREFIX G_DIR_SEPARATOR_S, + strlen (PREFIX G_DIR_SEPARATOR_S)) == 0) + { + /* This is a compile-time entry. Replace the path with the + * real one on this machine. + */ + p = *path; + *path = g_build_filename (gimp_installation_directory (), + *path + strlen (PREFIX G_DIR_SEPARATOR_S), + NULL); + g_free (p); + } +#endif +} + +/** + * gimp_path_parse: + * @path: A list of directories separated by #G_SEARCHPATH_SEPARATOR. + * @max_paths: The maximum number of directories to return. + * @check: %TRUE if you want the directories to be checked. + * @check_failed: Returns a #GList of path elements for which the + * check failed. + * + * Returns: A #GList of all directories in @path. + **/ +GList * +gimp_path_parse (const gchar *path, + gint max_paths, + gboolean check, + GList **check_failed) +{ + gchar **patharray; + GList *list = NULL; + GList *fail_list = NULL; + gint i; + gboolean exists = TRUE; + + if (!path || !*path || max_paths < 1 || max_paths > 256) + return NULL; + + patharray = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, max_paths); + + for (i = 0; i < max_paths; i++) + { + GString *dir; + + if (! patharray[i]) + break; + +#ifndef G_OS_WIN32 + if (*patharray[i] == '~') + { + dir = g_string_new (g_get_home_dir ()); + g_string_append (dir, patharray[i] + 1); + } + else +#endif + { + gimp_path_runtime_fix (&patharray[i]); + dir = g_string_new (patharray[i]); + } + + if (check) + exists = g_file_test (dir->str, G_FILE_TEST_IS_DIR); + + if (exists) + { + GList *dup; + + /* check for duplicate entries, see bug #784502 */ + for (dup = list; dup; dup = g_list_next (dup)) + { + if (! strcmp (dir->str, dup->data)) + break; + } + + /* only add to the list if it's not a duplicate */ + if (! dup) + list = g_list_prepend (list, g_strdup (dir->str)); + } + else if (check_failed) + { + fail_list = g_list_prepend (fail_list, g_strdup (dir->str)); + } + + g_string_free (dir, TRUE); + } + + g_strfreev (patharray); + + list = g_list_reverse (list); + + if (check && check_failed) + { + fail_list = g_list_reverse (fail_list); + *check_failed = fail_list; + } + + return list; +} + +/** + * gimp_path_to_str: + * @path: A list of directories as returned by gimp_path_parse(). + * + * Returns: A searchpath string separated by #G_SEARCHPATH_SEPARATOR. + **/ +gchar * +gimp_path_to_str (GList *path) +{ + GString *str = NULL; + GList *list; + gchar *retval = NULL; + + for (list = path; list; list = g_list_next (list)) + { + gchar *dir = list->data; + + if (str) + { + g_string_append_c (str, G_SEARCHPATH_SEPARATOR); + g_string_append (str, dir); + } + else + { + str = g_string_new (dir); + } + } + + if (str) + retval = g_string_free (str, FALSE); + + return retval; +} + +/** + * gimp_path_free: + * @path: A list of directories as returned by gimp_path_parse(). + * + * This function frees the memory allocated for the list and the strings + * it contains. + **/ +void +gimp_path_free (GList *path) +{ + g_list_free_full (path, (GDestroyNotify) g_free); +} + +/** + * gimp_path_get_user_writable_dir: + * @path: A list of directories as returned by gimp_path_parse(). + * + * Note that you have to g_free() the returned string. + * + * Returns: The first directory in @path where the user has write permission. + **/ +gchar * +gimp_path_get_user_writable_dir (GList *path) +{ + GList *list; + uid_t euid; + gid_t egid; + GStatBuf filestat; + gint err; + + g_return_val_if_fail (path != NULL, NULL); + + euid = geteuid (); + egid = getegid (); + + for (list = path; list; list = g_list_next (list)) + { + gchar *dir = list->data; + + /* check if directory exists */ + err = g_stat (dir, &filestat); + + /* this is tricky: + * if a file is e.g. owned by the current user but not user-writable, + * the user has no permission to write to the file regardless + * of his group's or other's write permissions + */ + if (!err && S_ISDIR (filestat.st_mode) && + + ((filestat.st_mode & S_IWUSR) || + + ((filestat.st_mode & S_IWGRP) && + (euid != filestat.st_uid)) || + + ((filestat.st_mode & S_IWOTH) && + (euid != filestat.st_uid) && + (egid != filestat.st_gid)))) + { + return g_strdup (dir); + } + } + + return NULL; +} + +static gchar * +gimp_env_get_dir (const gchar *gimp_env_name, + const gchar *compile_time_dir, + const gchar *relative_subdir) +{ + const gchar *env = g_getenv (gimp_env_name); + + if (env) + { + if (! g_path_is_absolute (env)) + g_error ("%s environment variable should be an absolute path.", + gimp_env_name); + + return g_strdup (env); + } + else if (compile_time_dir) + { + gchar *retval = g_strdup (compile_time_dir); + + gimp_path_runtime_fix (&retval); + + return retval; + } + else if (! g_path_is_absolute (relative_subdir)) + { + return g_build_filename (gimp_installation_directory (), + relative_subdir, + NULL); + } + + return g_strdup (relative_subdir); +} |