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