diff options
Diffstat (limited to 'glib/gutils.c')
-rw-r--r-- | glib/gutils.c | 235 |
1 files changed, 172 insertions, 63 deletions
diff --git a/glib/gutils.c b/glib/gutils.c index 78ccd6121..dce7cbee5 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -275,7 +275,44 @@ gchar* g_find_program_in_path (const gchar *program) #endif { - const gchar *path, *p; + return g_find_program_for_path (program, NULL, NULL); +} + +/** + * g_find_program_for_path: + * @program: (type filename): a program name in the GLib file name encoding + * @path: (type filename) (nullable): the current dir where to search program + * @working_dir: (type filename) (nullable): the working dir where to search + * program + * + * Locates the first executable named @program in @path, in the + * same way that execvp() would locate it. Returns an allocated string + * with the absolute path name (taking in account the @working_dir), or + * %NULL if the program is not found in @path. If @program is already an + * absolute path, returns a copy of @program if @program exists and is + * executable, and %NULL otherwise. + * + * On Windows, if @path is %NULL, it looks for the file in the same way as + * CreateProcess() would. This means first in the directory where the + * executing program was loaded from, then in the current directory, then in + * the Windows 32-bit system directory, then in the Windows directory, and + * finally in the directories in the `PATH` environment variable. If + * the program is found, the return value contains the full name + * including the type suffix. + * + * Returns: (type filename) (transfer full) (nullable): a newly-allocated + * string with the absolute path, or %NULL + * Since: 2.76 + **/ +char * +g_find_program_for_path (const char *program, + const char *path, + const char *working_dir) +{ + const char *original_path = path; + const char *original_program = program; + char *program_path = NULL; + const gchar *p; gchar *name, *freeme; #ifdef G_OS_WIN32 const gchar *path_copy; @@ -290,34 +327,59 @@ g_find_program_in_path (const gchar *program) g_return_val_if_fail (program != NULL, NULL); + /* Use the working dir as program path if provided */ + if (working_dir && !g_path_is_absolute (program)) + { + program_path = g_build_filename (working_dir, program, NULL); + program = program_path; + } + /* If it is an absolute path, or a relative path including subdirectories, * don't look in PATH. */ if (g_path_is_absolute (program) - || strchr (program, G_DIR_SEPARATOR) != NULL + || strchr (original_program, G_DIR_SEPARATOR) != NULL #ifdef G_OS_WIN32 - || strchr (program, '/') != NULL + || strchr (original_program, '/') != NULL #endif ) { if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (program, G_FILE_TEST_IS_DIR)) { - gchar *out = NULL, *cwd = NULL; + gchar *out = NULL; if (g_path_is_absolute (program)) - return g_strdup (program); + { + out = g_strdup (program); + } + else + { + char *cwd = g_get_current_dir (); + out = g_build_filename (cwd, program, NULL); + g_free (cwd); + } + + g_free (program_path); - cwd = g_get_current_dir (); - out = g_build_filename (cwd, program, NULL); - g_free (cwd); return g_steal_pointer (&out); } else - return NULL; + { + g_clear_pointer (&program_path, g_free); + + if (g_path_is_absolute (original_program)) + return NULL; + } } - - path = g_getenv ("PATH"); + + program = original_program; + + if G_LIKELY (original_path == NULL) + path = g_getenv ("PATH"); + else + path = original_path; + #if defined(G_OS_UNIX) if (path == NULL) { @@ -334,57 +396,65 @@ g_find_program_in_path (const gchar *program) path = "/bin:/usr/bin:."; } #else - n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN); - if (n > 0 && n < MAXPATHLEN) - filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL); - - n = GetSystemDirectoryW (wsysdir, MAXPATHLEN); - if (n > 0 && n < MAXPATHLEN) - sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL); - - n = GetWindowsDirectoryW (wwindir, MAXPATHLEN); - if (n > 0 && n < MAXPATHLEN) - windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL); - - if (filename) + if G_LIKELY (original_path == NULL) { - appdir = g_path_get_dirname (filename); - g_free (filename); - } - - path = g_strdup (path); + n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN); + if (n > 0 && n < MAXPATHLEN) + filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL); - if (windir) - { - const gchar *tem = path; - path = g_strconcat (windir, ";", path, NULL); - g_free ((gchar *) tem); - g_free (windir); - } - - if (sysdir) - { - const gchar *tem = path; - path = g_strconcat (sysdir, ";", path, NULL); - g_free ((gchar *) tem); - g_free (sysdir); + n = GetSystemDirectoryW (wsysdir, MAXPATHLEN); + if (n > 0 && n < MAXPATHLEN) + sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL); + + n = GetWindowsDirectoryW (wwindir, MAXPATHLEN); + if (n > 0 && n < MAXPATHLEN) + windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL); + + if (filename) + { + appdir = g_path_get_dirname (filename); + g_free (filename); + } + + path = g_strdup (path); + + if (windir) + { + const gchar *tem = path; + path = g_strconcat (windir, ";", path, NULL); + g_free ((gchar *) tem); + g_free (windir); + } + + if (sysdir) + { + const gchar *tem = path; + path = g_strconcat (sysdir, ";", path, NULL); + g_free ((gchar *) tem); + g_free (sysdir); + } + + { + const gchar *tem = path; + path = g_strconcat (".;", path, NULL); + g_free ((gchar *) tem); + } + + if (appdir) + { + const gchar *tem = path; + path = g_strconcat (appdir, ";", path, NULL); + g_free ((gchar *) tem); + g_free (appdir); + } + + path_copy = path; } - - { - const gchar *tem = path; - path = g_strconcat (".;", path, NULL); - g_free ((gchar *) tem); - } - - if (appdir) + else { - const gchar *tem = path; - path = g_strconcat (appdir, ";", path, NULL); - g_free ((gchar *) tem); - g_free (appdir); + path_copy = g_strdup (path); } - path_copy = path; #endif len = strlen (program) + 1; @@ -401,6 +471,7 @@ g_find_program_in_path (const gchar *program) do { char *startp; + char *startp_path = NULL; path = p; p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR); @@ -413,6 +484,13 @@ g_find_program_in_path (const gchar *program) else startp = memcpy (name - (p - path), path, p - path); + /* Use the working dir as program path if provided */ + if (working_dir && !g_path_is_absolute (startp)) + { + startp_path = g_build_filename (working_dir, startp, NULL); + startp = startp_path; + } + if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (startp, G_FILE_TEST_IS_DIR)) { @@ -425,15 +503,21 @@ g_find_program_in_path (const gchar *program) ret = g_build_filename (cwd, startp, NULL); g_free (cwd); } + + g_free (program_path); + g_free (startp_path); g_free (freeme); #ifdef G_OS_WIN32 g_free ((gchar *) path_copy); #endif return ret; } + + g_free (startp_path); } while (*p++ != '\0'); - + + g_free (program_path); g_free (freeme); #ifdef G_OS_WIN32 g_free ((gchar *) path_copy); @@ -521,6 +605,7 @@ 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; +static gchar *g_tmp_dir = NULL; /* fifteen minutes of fame for everybody */ #define G_USER_DIRS_EXPIRE 15 * 60 @@ -864,6 +949,17 @@ g_get_home_dir (void) return home_dir; } +void +_g_unset_cached_tmp_dir (void) +{ + G_LOCK (g_utils_global); + /* We have to leak the old value, as user code could be retaining pointers + * to it. */ + g_ignore_leak (g_tmp_dir); + g_tmp_dir = NULL; + G_UNLOCK (g_utils_global); +} + /** * g_get_tmp_dir: * @@ -887,22 +983,33 @@ g_get_home_dir (void) const gchar * g_get_tmp_dir (void) { - static gchar *tmp_dir; + G_LOCK (g_utils_global); - if (g_once_init_enter (&tmp_dir)) + if (g_tmp_dir == NULL) { gchar *tmp; + tmp = g_strdup (g_getenv ("G_TEST_TMPDIR")); + + if (tmp == NULL || *tmp == '\0') + { + g_free (tmp); + tmp = g_strdup (g_getenv ( #ifdef G_OS_WIN32 - tmp = g_strdup (g_getenv ("TEMP")); + "TEMP" +#else /* G_OS_WIN32 */ + "TMPDIR" +#endif /* G_OS_WIN32 */ + )); + } +#ifdef G_OS_WIN32 if (tmp == NULL || *tmp == '\0') { g_free (tmp); tmp = get_windows_directory_root (); } #else /* G_OS_WIN32 */ - tmp = g_strdup (g_getenv ("TMPDIR")); #ifdef P_tmpdir if (tmp == NULL || *tmp == '\0') @@ -923,10 +1030,12 @@ g_get_tmp_dir (void) } #endif /* !G_OS_WIN32 */ - g_once_init_leave (&tmp_dir, tmp); + g_tmp_dir = g_steal_pointer (&tmp); } - return tmp_dir; + G_UNLOCK (g_utils_global); + + return g_tmp_dir; } /** |