mirror of
https://github.com/neovim/neovim.git
synced 2025-10-01 07:28:34 +00:00
Merge #6741 from justinmk/progpath
This commit is contained in:
@@ -1749,9 +1749,7 @@ v:profiling Normally zero. Set to one after using ":profile start".
|
|||||||
See |profiling|.
|
See |profiling|.
|
||||||
|
|
||||||
*v:progname* *progname-variable*
|
*v:progname* *progname-variable*
|
||||||
v:progname Contains the name (with path removed) with which Nvim was
|
v:progname The name by which Nvim was invoked (with path removed).
|
||||||
invoked. Allows you to do special initialisations for any
|
|
||||||
name you might symlink to Nvim.
|
|
||||||
Read-only.
|
Read-only.
|
||||||
|
|
||||||
*v:progpath* *progpath-variable*
|
*v:progpath* *progpath-variable*
|
||||||
|
@@ -1223,7 +1223,8 @@ static void init_path(char *exename)
|
|||||||
size_t exepathlen = MAXPATHL;
|
size_t exepathlen = MAXPATHL;
|
||||||
// Make v:progpath absolute.
|
// Make v:progpath absolute.
|
||||||
if (os_exepath(exepath, &exepathlen) != 0) {
|
if (os_exepath(exepath, &exepathlen) != 0) {
|
||||||
EMSG2(e_intern2, "init_path()");
|
// Fall back to argv[0]. Missing procfs? #6734
|
||||||
|
path_guess_exepath(exename, exepath, sizeof(exepath));
|
||||||
}
|
}
|
||||||
set_vim_var_string(VV_PROGPATH, exepath, -1);
|
set_vim_var_string(VV_PROGPATH, exepath, -1);
|
||||||
set_vim_var_string(VV_PROGNAME, (char *)path_tail((char_u *)exename), -1);
|
set_vim_var_string(VV_PROGNAME, (char *)path_tail((char_u *)exename), -1);
|
||||||
@@ -1684,7 +1685,7 @@ static bool do_user_initialization(void)
|
|||||||
do {
|
do {
|
||||||
const char *dir;
|
const char *dir;
|
||||||
size_t dir_len;
|
size_t dir_len;
|
||||||
iter = vim_colon_env_iter(config_dirs, iter, &dir, &dir_len);
|
iter = vim_env_iter(':', config_dirs, iter, &dir, &dir_len);
|
||||||
if (dir == NULL || dir_len == 0) {
|
if (dir == NULL || dir_len == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -341,7 +341,7 @@ static inline size_t compute_double_colon_len(const char *const val,
|
|||||||
do {
|
do {
|
||||||
size_t dir_len;
|
size_t dir_len;
|
||||||
const char *dir;
|
const char *dir;
|
||||||
iter = vim_colon_env_iter(val, iter, &dir, &dir_len);
|
iter = vim_env_iter(':', val, iter, &dir, &dir_len);
|
||||||
if (dir != NULL && dir_len > 0) {
|
if (dir != NULL && dir_len > 0) {
|
||||||
ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
|
ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
|
||||||
+ !after_pathsep(dir, dir + dir_len)) * 2
|
+ !after_pathsep(dir, dir + dir_len)) * 2
|
||||||
@@ -385,8 +385,8 @@ static inline char *add_colon_dirs(char *dest, const char *const val,
|
|||||||
do {
|
do {
|
||||||
size_t dir_len;
|
size_t dir_len;
|
||||||
const char *dir;
|
const char *dir;
|
||||||
iter = (forward ? vim_colon_env_iter : vim_colon_env_iter_rev)(
|
iter = (forward ? vim_env_iter : vim_env_iter_rev)(':', val, iter, &dir,
|
||||||
val, iter, &dir, &dir_len);
|
&dir_len);
|
||||||
if (dir != NULL && dir_len > 0) {
|
if (dir != NULL && dir_len > 0) {
|
||||||
dest = strcpy_comma_escaped(dest, dir, dir_len);
|
dest = strcpy_comma_escaped(dest, dir, dir_len);
|
||||||
if (!after_pathsep(dest - 1, dest)) {
|
if (!after_pathsep(dest - 1, dest)) {
|
||||||
|
@@ -521,10 +521,11 @@ static char *remove_tail(char *path, char *pend, char *dirname)
|
|||||||
return pend;
|
return pend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over colon-separated list
|
/// Iterate over a delimited list.
|
||||||
///
|
///
|
||||||
/// @note Environment variables must not be modified during iteration.
|
/// @note Environment variables must not be modified during iteration.
|
||||||
///
|
///
|
||||||
|
/// @param[in] delim Delimiter character.
|
||||||
/// @param[in] val Value of the environment variable to iterate over.
|
/// @param[in] val Value of the environment variable to iterate over.
|
||||||
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
||||||
/// iteration.
|
/// iteration.
|
||||||
@@ -533,18 +534,19 @@ static char *remove_tail(char *path, char *pend, char *dirname)
|
|||||||
/// @param[out] len Location where current directory length should be saved.
|
/// @param[out] len Location where current directory length should be saved.
|
||||||
///
|
///
|
||||||
/// @return Next iter argument value or NULL when iteration should stop.
|
/// @return Next iter argument value or NULL when iteration should stop.
|
||||||
const void *vim_colon_env_iter(const char *const val,
|
const void *vim_env_iter(const char delim,
|
||||||
const void *const iter,
|
const char *const val,
|
||||||
const char **const dir,
|
const void *const iter,
|
||||||
size_t *const len)
|
const char **const dir,
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
|
size_t *const len)
|
||||||
|
FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
const char *varval = (const char *) iter;
|
const char *varval = (const char *) iter;
|
||||||
if (varval == NULL) {
|
if (varval == NULL) {
|
||||||
varval = val;
|
varval = val;
|
||||||
}
|
}
|
||||||
*dir = varval;
|
*dir = varval;
|
||||||
const char *const dirend = strchr(varval, ':');
|
const char *const dirend = strchr(varval, delim);
|
||||||
if (dirend == NULL) {
|
if (dirend == NULL) {
|
||||||
*len = strlen(varval);
|
*len = strlen(varval);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -554,10 +556,11 @@ const void *vim_colon_env_iter(const char *const val,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over colon-separated list in reverse order
|
/// Iterate over a delimited list in reverse order.
|
||||||
///
|
///
|
||||||
/// @note Environment variables must not be modified during iteration.
|
/// @note Environment variables must not be modified during iteration.
|
||||||
///
|
///
|
||||||
|
/// @param[in] delim Delimiter character.
|
||||||
/// @param[in] val Value of the environment variable to iterate over.
|
/// @param[in] val Value of the environment variable to iterate over.
|
||||||
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
||||||
/// iteration.
|
/// iteration.
|
||||||
@@ -566,18 +569,19 @@ const void *vim_colon_env_iter(const char *const val,
|
|||||||
/// @param[out] len Location where current directory length should be saved.
|
/// @param[out] len Location where current directory length should be saved.
|
||||||
///
|
///
|
||||||
/// @return Next iter argument value or NULL when iteration should stop.
|
/// @return Next iter argument value or NULL when iteration should stop.
|
||||||
const void *vim_colon_env_iter_rev(const char *const val,
|
const void *vim_env_iter_rev(const char delim,
|
||||||
const void *const iter,
|
const char *const val,
|
||||||
const char **const dir,
|
const void *const iter,
|
||||||
size_t *const len)
|
const char **const dir,
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
|
size_t *const len)
|
||||||
|
FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
const char *varend = (const char *) iter;
|
const char *varend = (const char *) iter;
|
||||||
if (varend == NULL) {
|
if (varend == NULL) {
|
||||||
varend = val + strlen(val) - 1;
|
varend = val + strlen(val) - 1;
|
||||||
}
|
}
|
||||||
const size_t varlen = (size_t) (varend - val) + 1;
|
const size_t varlen = (size_t)(varend - val) + 1;
|
||||||
const char *const colon = xmemrchr(val, ':', varlen);
|
const char *const colon = xmemrchr(val, (uint8_t)delim, varlen);
|
||||||
if (colon == NULL) {
|
if (colon == NULL) {
|
||||||
*len = varlen;
|
*len = varlen;
|
||||||
*dir = val;
|
*dir = val;
|
||||||
@@ -634,18 +638,17 @@ char *vim_getenv(const char *name)
|
|||||||
char exe_name[MAXPATHL];
|
char exe_name[MAXPATHL];
|
||||||
// Find runtime path relative to the nvim binary: ../share/nvim/runtime
|
// Find runtime path relative to the nvim binary: ../share/nvim/runtime
|
||||||
if (vim_path == NULL) {
|
if (vim_path == NULL) {
|
||||||
size_t exe_name_len = MAXPATHL;
|
xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH),
|
||||||
if (os_exepath(exe_name, &exe_name_len) == 0) {
|
sizeof(exe_name));
|
||||||
char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
|
char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
|
||||||
*path_end = '\0'; // remove the trailing "nvim.exe"
|
*path_end = '\0'; // remove the trailing "nvim.exe"
|
||||||
path_end = (char *)path_tail((char_u *)exe_name);
|
path_end = (char *)path_tail((char_u *)exe_name);
|
||||||
*path_end = '\0'; // remove the trailing "bin/"
|
*path_end = '\0'; // remove the trailing "bin/"
|
||||||
if (append_path(
|
if (append_path(
|
||||||
exe_name,
|
exe_name,
|
||||||
"share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
|
"share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
|
||||||
MAXPATHL) == OK) {
|
MAXPATHL) == OK) {
|
||||||
vim_path = exe_name; // -V507
|
vim_path = exe_name; // -V507
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -196,11 +196,13 @@ int os_nodetype(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the absolute path of the currently running executable.
|
/// Gets the absolute path of the currently running executable.
|
||||||
|
/// May fail if procfs is missing. #6734
|
||||||
|
/// @see path_exepath
|
||||||
///
|
///
|
||||||
/// @param[out] buffer Returns the path string.
|
/// @param[out] buffer Full path to the executable.
|
||||||
/// @param[in] size Size of `buffer`.
|
/// @param[in] size Size of `buffer`.
|
||||||
///
|
///
|
||||||
/// @return `0` on success, or libuv error code on failure.
|
/// @return 0 on success, or libuv error code.
|
||||||
int os_exepath(char *buffer, size_t *size)
|
int os_exepath(char *buffer, size_t *size)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
@@ -2237,3 +2237,50 @@ int path_is_absolute_path(const char_u *fname)
|
|||||||
return *fname == '/' || *fname == '~';
|
return *fname == '/' || *fname == '~';
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a full path from an invocation name `argv0`, based on heuristics.
|
||||||
|
///
|
||||||
|
/// @param[in] argv0 Name by which Nvim was invoked.
|
||||||
|
/// @param[out] buf Guessed full path to `argv0`.
|
||||||
|
/// @param[in] bufsize Size of `buf`.
|
||||||
|
///
|
||||||
|
/// @see os_exepath
|
||||||
|
void path_guess_exepath(const char *argv0, char *buf, size_t bufsize)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
char *path = getenv("PATH");
|
||||||
|
|
||||||
|
if (path == NULL || path_is_absolute_path((char_u *)argv0)) {
|
||||||
|
xstrlcpy(buf, argv0, bufsize);
|
||||||
|
} else if (argv0[0] == '.' || strchr(argv0, PATHSEP)) {
|
||||||
|
// Relative to CWD.
|
||||||
|
if (os_dirname((char_u *)buf, MAXPATHL) != OK) {
|
||||||
|
buf[0] = NUL;
|
||||||
|
}
|
||||||
|
xstrlcat(buf, PATHSEPSTR, bufsize);
|
||||||
|
xstrlcat(buf, argv0, bufsize);
|
||||||
|
} else {
|
||||||
|
// Search $PATH for plausible location.
|
||||||
|
const void *iter = NULL;
|
||||||
|
do {
|
||||||
|
const char *dir;
|
||||||
|
size_t dir_len;
|
||||||
|
iter = vim_env_iter(ENV_SEPCHAR, path, iter, &dir, &dir_len);
|
||||||
|
if (dir == NULL || dir_len == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dir_len + 1 > sizeof(NameBuff)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xstrlcpy((char *)NameBuff, dir, dir_len + 1);
|
||||||
|
xstrlcat((char *)NameBuff, PATHSEPSTR, sizeof(NameBuff));
|
||||||
|
xstrlcat((char *)NameBuff, argv0, sizeof(NameBuff));
|
||||||
|
if (os_can_exe(NameBuff, NULL, false)) {
|
||||||
|
xstrlcpy(buf, (char *)NameBuff, bufsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (iter != NULL);
|
||||||
|
// Not found in $PATH, fall back to argv0.
|
||||||
|
xstrlcpy(buf, argv0, bufsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -13,7 +13,7 @@ require('lfs')
|
|||||||
|
|
||||||
local cimp = cimport('./src/nvim/os/os.h')
|
local cimp = cimport('./src/nvim/os/os.h')
|
||||||
|
|
||||||
describe('env function', function()
|
describe('env.c', function()
|
||||||
local function os_setenv(name, value, override)
|
local function os_setenv(name, value, override)
|
||||||
return cimp.os_setenv(to_cstr(name), to_cstr(value), override)
|
return cimp.os_setenv(to_cstr(name), to_cstr(value), override)
|
||||||
end
|
end
|
||||||
|
@@ -18,7 +18,7 @@ local cimp = cimport('./src/nvim/os/os.h', './src/nvim/path.h')
|
|||||||
local length = 0
|
local length = 0
|
||||||
local buffer = nil
|
local buffer = nil
|
||||||
|
|
||||||
describe('path function', function()
|
describe('path.c', function()
|
||||||
describe('path_full_dir_name', function()
|
describe('path_full_dir_name', function()
|
||||||
setup(function()
|
setup(function()
|
||||||
lfs.mkdir('unit-test-directory')
|
lfs.mkdir('unit-test-directory')
|
||||||
@@ -293,6 +293,59 @@ describe('path_shorten_fname_if_possible', function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('path.c path_guess_exepath', function()
|
||||||
|
local cwd = lfs.currentdir()
|
||||||
|
|
||||||
|
for _,name in ipairs({'./nvim', '.nvim', 'foo/nvim'}) do
|
||||||
|
itp('"'..name..'" returns name catenated with CWD', function()
|
||||||
|
local bufsize = 255
|
||||||
|
local buf = cstr(bufsize, '')
|
||||||
|
cimp.path_guess_exepath(name, buf, bufsize)
|
||||||
|
eq(cwd..'/'..name, ffi.string(buf))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
itp('absolute path returns the name unmodified', function()
|
||||||
|
local name = '/foo/bar/baz'
|
||||||
|
local bufsize = 255
|
||||||
|
local buf = cstr(bufsize, '')
|
||||||
|
cimp.path_guess_exepath(name, buf, bufsize)
|
||||||
|
eq(name, ffi.string(buf))
|
||||||
|
end)
|
||||||
|
|
||||||
|
itp('returns the name unmodified if not found in $PATH', function()
|
||||||
|
local name = '23u0293_not_in_path'
|
||||||
|
local bufsize = 255
|
||||||
|
local buf = cstr(bufsize, '')
|
||||||
|
cimp.path_guess_exepath(name, buf, bufsize)
|
||||||
|
eq(name, ffi.string(buf))
|
||||||
|
end)
|
||||||
|
|
||||||
|
itp('does not crash if $PATH item exceeds MAXPATHL', function()
|
||||||
|
local orig_path_env = os.getenv('PATH')
|
||||||
|
local name = 'cat' -- Some executable in $PATH.
|
||||||
|
local bufsize = 255
|
||||||
|
local buf = cstr(bufsize, '')
|
||||||
|
local insane_path = orig_path_env..':'..(("x/"):rep(4097))
|
||||||
|
|
||||||
|
cimp.os_setenv('PATH', insane_path, true)
|
||||||
|
cimp.path_guess_exepath(name, buf, bufsize)
|
||||||
|
eq('bin/' .. name, ffi.string(buf):sub(-#('bin/' .. name), -1))
|
||||||
|
|
||||||
|
-- Restore $PATH.
|
||||||
|
cimp.os_setenv('PATH', orig_path_env, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
itp('returns full path found in $PATH', function()
|
||||||
|
local name = 'cat' -- Some executable in $PATH.
|
||||||
|
local bufsize = 255
|
||||||
|
local buf = cstr(bufsize, '')
|
||||||
|
cimp.path_guess_exepath(name, buf, bufsize)
|
||||||
|
-- Usually "/bin/cat" on unix, "/path/to/nvim/cat" on Windows.
|
||||||
|
eq('bin/' .. name, ffi.string(buf):sub(-#('bin/' .. name), -1))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
describe('path.c', function()
|
describe('path.c', function()
|
||||||
setup(function()
|
setup(function()
|
||||||
lfs.mkdir('unit-test-directory');
|
lfs.mkdir('unit-test-directory');
|
||||||
|
Reference in New Issue
Block a user