summaryrefslogtreecommitdiff
path: root/glib/gutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'glib/gutils.c')
-rw-r--r--glib/gutils.c235
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;
}
/**