win: executable()

Windows: prepend `".;"` to PATH, as Vim does.
c4a249a736/src/os_win32.c (L1916)
This commit is contained in:
Justin M. Keyes 2017-02-01 02:25:40 +01:00
parent 3d3b1641d0
commit 8371d6fb07

View File

@ -223,11 +223,14 @@ bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
// need to use $PATH.
if (!use_path || path_is_absolute_path(name)
|| (name[0] == '.'
&& (name[1] == '/'
|| (name[1] == '.' && name[2] == '/')))) {
// There must be a path separator, files in the current directory
// can't be executed
if (gettail_dir(name) != name && is_executable(name)) {
&& (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) {
#if WIN32
bool ok = is_executable(name);
#else
// Must have path separator, cannot execute files in the current directory.
bool ok = gettail_dir(name) != name && is_executable(name);
#endif
if (ok) {
if (abspath != NULL) {
*abspath = save_absolute_path(name);
}
@ -259,8 +262,6 @@ static bool is_executable(const char_u *name)
#else
return (S_ISREG(mode) && (S_IXUSR & mode));
#endif
return false;
}
/// Checks if a file is inside the `$PATH` and is executable.
@ -272,12 +273,21 @@ static bool is_executable(const char_u *name)
static bool is_executable_in_path(const char_u *name, char_u **abspath)
FUNC_ATTR_NONNULL_ARG(1)
{
const char *path = os_getenv("PATH");
if (path == NULL) {
const char *path_env = os_getenv("PATH");
if (path_env == NULL) {
return false;
}
size_t buf_len = STRLEN(name) + STRLEN(path) + 2;
#ifdef WIN32
// Prepend ".;" to $PATH.
size_t pathlen = strlen(path_env);
char *path = memcpy(xmallocz(pathlen + 3), ".;", 2);
memcpy(path + 2, path_env, pathlen);
#else
char *path = xstrdup(path_env);
#endif
size_t buf_len = STRLEN(name) + strlen(path) + 2;
#ifdef WIN32
const char *pathext = os_getenv("PATHEXT");
@ -285,20 +295,21 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
pathext = ".com;.exe;.bat;.cmd";
}
buf_len += STRLEN(pathext);
buf_len += strlen(pathext);
#endif
char_u *buf = xmalloc(buf_len);
// Walk through all entries in $PATH to check if "name" exists there and
// is an executable file.
char *p = path;
bool rv = false;
for (;; ) {
const char *e = xstrchrnul(path, ENV_SEPCHAR);
char *e = xstrchrnul(p, ENV_SEPCHAR);
// Glue together the given directory from $PATH with name and save into
// buf.
STRLCPY(buf, path, e - path + 1);
append_path((char *) buf, (const char *) name, buf_len);
// Glue the directory from $PATH with `name` and save into buf.
STRLCPY(buf, p, e - p + 1);
append_path((char *)buf, (char *)name, buf_len);
if (is_executable(buf)) {
// Check if the caller asked for a copy of the path.
@ -306,9 +317,8 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
*abspath = save_absolute_path(buf);
}
xfree(buf);
return true;
rv = true;
goto end;
}
#ifdef WIN32
@ -316,9 +326,8 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
char *buf_end = xstrchrnul((char *)buf, '\0');
for (const char *ext = pathext; *ext; ext++) {
// Skip the extension if there is no suffix after a '.'.
if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ';')) {
if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) {
*ext++;
continue;
}
@ -331,9 +340,8 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
*abspath = save_absolute_path(buf);
}
xfree(buf);
return true;
rv = true;
goto end;
}
if (*ext_end != ENV_SEPCHAR) {
@ -345,16 +353,16 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
if (*e != ENV_SEPCHAR) {
// End of $PATH without finding any executable called name.
xfree(buf);
return false;
goto end;
}
path = e + 1;
p = e + 1;
}
// We should never get to this point.
assert(false);
return false;
end:
xfree(buf);
xfree(path);
return rv;
}
/// Opens or creates a file and returns a non-negative integer representing