aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/os/fs.c88
-rw-r--r--src/os/os.h1
-rw-r--r--src/os_unix.c65
-rw-r--r--src/os_unix.h1
-rw-r--r--test/unit/os_unix.moon38
5 files changed, 102 insertions, 91 deletions
diff --git a/src/os/fs.c b/src/os/fs.c
index 6ae48ab269..a1e3cd2899 100644
--- a/src/os/fs.c
+++ b/src/os/fs.c
@@ -15,6 +15,7 @@
#include "os.h"
#include "../message.h"
+#include "../misc1.h"
#include "../misc2.h"
int mch_chdir(char *path) {
@@ -40,7 +41,7 @@ int mch_dirname(char_u *buf, int len)
return OK;
}
-/*
+/*
* Get the absolute name of the given relative directory.
*
* parameter directory: Directory name, relative to current directory.
@@ -85,7 +86,7 @@ int mch_full_dir_name(char *directory, char *buffer, int len)
return retval;
}
-/*
+/*
* Append to_append to path with a slash in between.
*/
int append_path(char *path, char *to_append, int max_len)
@@ -191,3 +192,86 @@ int mch_isdir(char_u *name)
return TRUE;
}
+int is_executable(char_u *name);
+
+/*
+ * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
+ */
+int is_executable(char_u *name)
+{
+ uv_fs_t request;
+ if (0 != uv_fs_stat(uv_default_loop(), &request, (const char*) name, NULL)) {
+ return FALSE;
+ }
+
+ if (S_ISREG(request.statbuf.st_mode) &&
+ (S_IEXEC & request.statbuf.st_mode)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Return 1 if "name" can be found in $PATH and executed, 0 if not.
+ * Return -1 if unknown.
+ */
+int mch_can_exe(char_u *name)
+{
+ char_u *buf;
+ char_u *path, *e;
+ int retval;
+
+ /* If it's an absolute or relative path don't need to use $PATH. */
+ if (mch_is_absolute_path(name) ||
+ (name[0] == '.' && (name[1] == '/' ||
+ (name[1] == '.' && name[2] == '/')))) {
+ return is_executable(name);
+ }
+
+ path = (char_u *)getenv("PATH");
+ /* PATH environment variable does not exist or is empty. */
+ if (path == NULL || *path == NUL) {
+ return -1;
+ }
+
+ int buf_len = STRLEN(name) + STRLEN(path) + 2;
+ buf = alloc((unsigned)(buf_len));
+ if (buf == NULL) {
+ return -1;
+ }
+
+ /*
+ * Walk through all entries in $PATH to check if "name" exists there and
+ * is an executable file.
+ */
+ for (;; ) {
+ e = (char_u *)strchr((char *)path, ':');
+ if (e == NULL) {
+ e = path + STRLEN(path);
+ }
+
+ if (e - path <= 1) { /* empty entry means current dir */
+ STRCPY(buf, "./");
+ } else {
+ vim_strncpy(buf, path, e - path);
+ add_pathsep(buf);
+ }
+
+ append_path((char *) buf, (char *) name, buf_len);
+
+ retval = is_executable(buf);
+ if (retval == OK) {
+ break;
+ }
+
+ if (*e != ':') {
+ break;
+ }
+
+ path = e + 1;
+ }
+
+ vim_free(buf);
+ return retval;
+}
diff --git a/src/os/os.h b/src/os/os.h
index 266b253e86..1d3a0d2c2b 100644
--- a/src/os/os.h
+++ b/src/os/os.h
@@ -9,6 +9,7 @@ int mch_dirname(char_u *buf, int len);
int mch_get_absolute_path(char_u *fname, char_u *buf, int len, int force);
int mch_is_absolute_path(char_u *fname);
int mch_isdir(char_u *name);
+int mch_can_exe(char_u *name);
const char *mch_getenv(const char *name);
int mch_setenv(const char *name, const char *value, int overwrite);
char *mch_getenvname_at_index(size_t index);
diff --git a/src/os_unix.c b/src/os_unix.c
index 5a01f07c36..3bbe056cc6 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -1319,71 +1319,6 @@ void mch_hide(char_u *name)
/* can't hide a file */
}
-int executable_file(char_u *name);
-
-/*
- * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
- */
-int executable_file(char_u *name)
-{
- struct stat st;
-
- if (stat((char *)name, &st))
- return 0;
- return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
-}
-
-/*
- * Return 1 if "name" can be found in $PATH and executed, 0 if not.
- * Return -1 if unknown.
- */
-int mch_can_exe(char_u *name)
-{
- char_u *buf;
- char_u *p, *e;
- int retval;
-
- /* If it's an absolute or relative path don't need to use $PATH. */
- if (mch_is_absolute_path(name) || (name[0] == '.' && (name[1] == '/'
- || (name[1] == '.' &&
- name[2] == '/'))))
- return executable_file(name);
-
- p = (char_u *)mch_getenv("PATH");
- if (p == NULL || *p == NUL)
- return -1;
- buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
- if (buf == NULL)
- return -1;
-
- /*
- * Walk through all entries in $PATH to check if "name" exists there and
- * is an executable file.
- */
- for (;; ) {
- e = (char_u *)strchr((char *)p, ':');
- if (e == NULL)
- e = p + STRLEN(p);
- if (e - p <= 1) /* empty entry means current dir */
- STRCPY(buf, "./");
- else {
- vim_strncpy(buf, p, e - p);
- add_pathsep(buf);
- }
- STRCAT(buf, name);
- retval = executable_file(buf);
- if (retval == 1)
- break;
-
- if (*e != ':')
- break;
- p = e + 1;
- }
-
- vim_free(buf);
- return retval;
-}
-
/*
* Check what "name" is:
* NODE_NORMAL: file or directory (or doesn't exist)
diff --git a/src/os_unix.h b/src/os_unix.h
index 92222bbca6..606237ee80 100644
--- a/src/os_unix.h
+++ b/src/os_unix.h
@@ -37,7 +37,6 @@ vim_acl_T mch_get_acl(char_u *fname);
void mch_set_acl(char_u *fname, vim_acl_T aclent);
void mch_free_acl(vim_acl_T aclent);
void mch_hide(char_u *name);
-int mch_can_exe(char_u *name);
int mch_nodetype(char_u *name);
void mch_early_init(void);
void mch_free_mem(void);
diff --git a/test/unit/os_unix.moon b/test/unit/os_unix.moon
index ea054ab020..09505235d7 100644
--- a/test/unit/os_unix.moon
+++ b/test/unit/os_unix.moon
@@ -7,7 +7,7 @@ enum BOOLEAN {
TRUE = 1, FALSE = 0
};
int mch_isdir(char_u * name);
-int executable_file(char_u *name);
+int is_executable(char_u *name);
int mch_can_exe(char_u *name);
]]
@@ -22,15 +22,13 @@ describe 'os_unix function', ->
-- that executable for several asserts.
export absolute_executable = arg[0]
- -- Split absolute_executable into a directory and the actual file name and
- -- append the directory to $PATH.
- export directory, executable = if (string.find absolute_executable, '/')
+ -- Split absolute_executable into a directory and the actual file name for
+ -- later usage.
+ export directory, executable_name = if (string.find absolute_executable, '/')
string.match(absolute_executable, '^(.*)/(.*)$')
else
string.match(absolute_executable, '^(.*)\\(.*)$')
- package.path = package.path .. ';' .. directory
-
teardown ->
lfs.rmdir 'unit-test-directory'
@@ -57,25 +55,25 @@ describe 'os_unix function', ->
it 'returns true if an arbitrary directory is given', ->
eq TRUE, (mch_isdir 'unit-test-directory')
- describe 'executable_file', ->
- executable_file = (name) ->
+ describe 'is_executable', ->
+ is_executable = (name) ->
name = cstr (string.len name), name
- os.executable_file name
+ os.is_executable name
it 'returns false when given a directory', ->
- eq FALSE, (executable_file 'unit-test-directory')
+ eq FALSE, (is_executable 'unit-test-directory')
it 'returns false when the given file does not exists', ->
- eq FALSE, (executable_file 'does-not-exist.file')
+ eq FALSE, (is_executable 'does-not-exist.file')
it 'returns true when given an executable regular file', ->
- eq TRUE, (executable_file absolute_executable)
+ eq TRUE, (is_executable absolute_executable)
it 'returns false when given a regular file without executable bit set', ->
-- This is a critical test since Windows does not have any executable
- -- bit. Thus executable_file returns TRUE on every regular file on
+ -- bit. Thus is_executable returns TRUE on every regular file on
-- Windows and this test will fail.
- eq FALSE, (executable_file 'unit-test-directory/test.file')
+ eq FALSE, (is_executable 'unit-test-directory/test.file')
describe 'mch_can_exe', ->
mch_can_exe = (name) ->
@@ -83,23 +81,17 @@ describe 'os_unix function', ->
os.mch_can_exe name
it 'returns false when given a directory', ->
- eq FALSE, (mch_can_exe 'unit-test-directory')
+ eq FALSE, (mch_can_exe './unit-test-directory')
it 'returns false when the given file does not exists', ->
eq FALSE, (mch_can_exe 'does-not-exist.file')
- it 'returns true when given an executable in the current directory', ->
- old_dir = lfs.currentdir!
- lfs.chdir directory
- eq TRUE, (mch_can_exe executable)
- lfs.chdir old_dir
-
it 'returns true when given an executable inside $PATH', ->
- eq TRUE, (mch_can_exe executable)
+ eq TRUE, (mch_can_exe executable_name)
it 'returns true when given an executable relative to the current dir', ->
old_dir = lfs.currentdir!
lfs.chdir directory
- relative_executable = './' .. executable
+ relative_executable = './' .. executable_name
eq TRUE, (mch_can_exe relative_executable)
lfs.chdir old_dir