From 00988d0d76dd765f654fb88265d11a59355eaf50 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 1 Mar 2001 10:25:12 +0000 Subject: [PATCH] Implement on Win32. Append the executable file name suffixes from PATHEXT 2001-03-01 Tor Lillqvist * gutils.c(g_find_program_in_path): Implement on Win32. Append the executable file name suffixes from PATHEXT in turn while looking for the program. (g_find_program_in_path): If the program we are looking for is a relative path in a subdirectory, don't do any path search. --- ChangeLog | 8 +++++-- ChangeLog.pre-2-0 | 8 +++++-- ChangeLog.pre-2-10 | 8 +++++-- ChangeLog.pre-2-12 | 8 +++++-- ChangeLog.pre-2-2 | 8 +++++-- ChangeLog.pre-2-4 | 8 +++++-- ChangeLog.pre-2-6 | 8 +++++-- ChangeLog.pre-2-8 | 8 +++++-- glib/gutils.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---- gutils.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++---- testglib.c | 2 +- tests/testglib.c | 2 +- 12 files changed, 174 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3dc4cb..66f914d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index b3dc4cb..66f914d 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -3,12 +3,16 @@ * gutils.c (g_path_is_absolute): (Win32) Remove test for initial double backslash (UNC path), this will of course be matched by the test for an initial G_DIR_SEPARATOR right up front. Silly me. - (g_find_program_in_path): Implement on Win32. + (g_find_program_in_path): Implement on Win32. Append the + executable file name suffixes from PATHEXT in turn while looking + for the program. + (g_find_program_in_path): If the program we are looking for is a + relative path in a subdirectory, don't do any path search. (g_get_any_init): (Win32) Also look for the USERPROFILE env var indicating the home directory equivalent. * testglib.c (main): Test g_find_program_in_path() on Win32 by - looking for more.com and regedit.exe. + looking for more.com and regedit. * glib.def: Add g_find_program_in_path. diff --git a/glib/gutils.c b/glib/gutils.c index 1c89877..be7feb6 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -157,6 +157,52 @@ my_strchrnul (const gchar *str, gchar c) return p; } +#ifdef G_OS_WIN32 + +gchar *inner_find_program_in_path (const gchar *program); + +gchar* +g_find_program_in_path (const gchar *program) +{ + const gchar *last_dot = strrchr (program, '.'); + + if (last_dot == NULL || strchr (last_dot, '\\') != NULL) + { + const gint program_length = strlen (program); + const gchar *pathext = getenv ("PATHEXT"); + const gchar *p; + gchar *decorated_program; + gchar *retval; + + if (pathext == NULL) + pathext = ".com;.exe;.bat"; + + p = pathext; + do + { + pathext = p; + p = my_strchrnul (pathext, ';'); + + decorated_program = g_malloc (program_length + (p-pathext) + 1); + memcpy (decorated_program, program, program_length); + memcpy (decorated_program+program_length, pathext, p-pathext); + decorated_program [program_length + (p-pathext)] = '\0'; + + retval = inner_find_program_in_path (decorated_program); + g_free (decorated_program); + + if (retval != NULL) + return retval; + } while (*p++ != '\0'); + return NULL; + } + else + return inner_find_program_in_path (program); +} + +#define g_find_program_in_path inner_find_program_in_path +#endif + /** * g_find_program_in_path: * @program: a program name @@ -167,6 +213,17 @@ my_strchrnul (const gchar *str, gchar c) * the 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 @program does not have a file type suffix, tries to + * append the suffixes in the PATHEXT environment variable (if that + * doesn't exists, the suffixes .com, .exe, and .bat) in turn, and + * then look for the resulting file name in the same way as + * CreateProcess() would. This means first in the directory where the + * 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. + * * Return value: absolute path, or NULL **/ gchar* @@ -180,13 +237,13 @@ g_find_program_in_path (const gchar *program) size_t len; size_t pathlen; - /* On Win32, should we try appending .exe, .com, and the other - * components of %PATHEXT% ? - */ - g_return_val_if_fail (program != NULL, NULL); - if (g_path_is_absolute (program)) + /* 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) { if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE)) return g_strdup (program); diff --git a/gutils.c b/gutils.c index 1c89877..be7feb6 100644 --- a/gutils.c +++ b/gutils.c @@ -157,6 +157,52 @@ my_strchrnul (const gchar *str, gchar c) return p; } +#ifdef G_OS_WIN32 + +gchar *inner_find_program_in_path (const gchar *program); + +gchar* +g_find_program_in_path (const gchar *program) +{ + const gchar *last_dot = strrchr (program, '.'); + + if (last_dot == NULL || strchr (last_dot, '\\') != NULL) + { + const gint program_length = strlen (program); + const gchar *pathext = getenv ("PATHEXT"); + const gchar *p; + gchar *decorated_program; + gchar *retval; + + if (pathext == NULL) + pathext = ".com;.exe;.bat"; + + p = pathext; + do + { + pathext = p; + p = my_strchrnul (pathext, ';'); + + decorated_program = g_malloc (program_length + (p-pathext) + 1); + memcpy (decorated_program, program, program_length); + memcpy (decorated_program+program_length, pathext, p-pathext); + decorated_program [program_length + (p-pathext)] = '\0'; + + retval = inner_find_program_in_path (decorated_program); + g_free (decorated_program); + + if (retval != NULL) + return retval; + } while (*p++ != '\0'); + return NULL; + } + else + return inner_find_program_in_path (program); +} + +#define g_find_program_in_path inner_find_program_in_path +#endif + /** * g_find_program_in_path: * @program: a program name @@ -167,6 +213,17 @@ my_strchrnul (const gchar *str, gchar c) * the 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 @program does not have a file type suffix, tries to + * append the suffixes in the PATHEXT environment variable (if that + * doesn't exists, the suffixes .com, .exe, and .bat) in turn, and + * then look for the resulting file name in the same way as + * CreateProcess() would. This means first in the directory where the + * 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. + * * Return value: absolute path, or NULL **/ gchar* @@ -180,13 +237,13 @@ g_find_program_in_path (const gchar *program) size_t len; size_t pathlen; - /* On Win32, should we try appending .exe, .com, and the other - * components of %PATHEXT% ? - */ - g_return_val_if_fail (program != NULL, NULL); - if (g_path_is_absolute (program)) + /* 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) { if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE)) return g_strdup (program); diff --git a/testglib.c b/testglib.c index bdb7b09..1e1adf3 100644 --- a/testglib.c +++ b/testglib.c @@ -1167,7 +1167,7 @@ main (int argc, g_win32_get_package_installation_directory ("gtk20", NULL)); g_print ("found more.com as %s\n", g_find_program_in_path ("more.com")); - g_print ("found regedit.exe as %s\n", g_find_program_in_path ("regedit.exe")); + g_print ("found regedit as %s\n", g_find_program_in_path ("regedit")); #endif diff --git a/tests/testglib.c b/tests/testglib.c index bdb7b09..1e1adf3 100644 --- a/tests/testglib.c +++ b/tests/testglib.c @@ -1167,7 +1167,7 @@ main (int argc, g_win32_get_package_installation_directory ("gtk20", NULL)); g_print ("found more.com as %s\n", g_find_program_in_path ("more.com")); - g_print ("found regedit.exe as %s\n", g_find_program_in_path ("regedit.exe")); + g_print ("found regedit as %s\n", g_find_program_in_path ("regedit")); #endif -- 2.7.4