mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #2148 'misc1.c: split some environment functions'
This commit is contained in:
commit
e16ff72e71
@ -1744,7 +1744,7 @@ ex_let_one (
|
|||||||
name[len] = NUL;
|
name[len] = NUL;
|
||||||
p = get_tv_string_chk(tv);
|
p = get_tv_string_chk(tv);
|
||||||
if (p != NULL && op != NULL && *op == '.') {
|
if (p != NULL && op != NULL && *op == '.') {
|
||||||
int mustfree = FALSE;
|
bool mustfree = false;
|
||||||
char_u *s = vim_getenv(name, &mustfree);
|
char_u *s = vim_getenv(name, &mustfree);
|
||||||
|
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
@ -6300,7 +6300,7 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
{
|
{
|
||||||
char_u *name;
|
char_u *name;
|
||||||
char_u *string = NULL;
|
char_u *string = NULL;
|
||||||
int mustfree = FALSE;
|
bool mustfree = false;
|
||||||
int len;
|
int len;
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
|
@ -5059,7 +5059,7 @@ void fix_help_buffer(void)
|
|||||||
char_u *fname;
|
char_u *fname;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
char_u *rt;
|
char_u *rt;
|
||||||
int mustfree;
|
bool mustfree;
|
||||||
|
|
||||||
/* set filetype to "help". */
|
/* set filetype to "help". */
|
||||||
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
|
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
|
||||||
|
@ -3808,7 +3808,7 @@ expand_shellcmd (
|
|||||||
char_u *pat;
|
char_u *pat;
|
||||||
int i;
|
int i;
|
||||||
char_u *path;
|
char_u *path;
|
||||||
int mustfree = FALSE;
|
bool mustfree = false;
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
char_u *buf = xmalloc(MAXPATHL);
|
char_u *buf = xmalloc(MAXPATHL);
|
||||||
size_t l;
|
size_t l;
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/os/event.h"
|
#include "nvim/os/event.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
|
#include "nvim/os/os.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These buffers are used for storing:
|
* These buffers are used for storing:
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc1.h"
|
|
||||||
#include "nvim/misc2.h"
|
#include "nvim/misc2.h"
|
||||||
#include "nvim/garray.h"
|
#include "nvim/garray.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc1.h"
|
|
||||||
#include "nvim/misc2.h"
|
#include "nvim/misc2.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "nvim/log.h"
|
#include "nvim/log.h"
|
||||||
#include "nvim/misc1.h"
|
|
||||||
#include "nvim/types.h"
|
#include "nvim/types.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
|
@ -818,7 +818,7 @@ static void init_locale(void)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
{
|
{
|
||||||
int mustfree = FALSE;
|
bool mustfree = false;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
/* expand_env() doesn't work yet, because chartab[] is not initialized
|
/* expand_env() doesn't work yet, because chartab[] is not initialized
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc1.h"
|
|
||||||
#include "nvim/misc2.h"
|
#include "nvim/misc2.h"
|
||||||
#include "nvim/normal.h"
|
#include "nvim/normal.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
|
@ -56,7 +56,6 @@
|
|||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc1.h"
|
|
||||||
#include "nvim/misc2.h"
|
#include "nvim/misc2.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/os_unix.h"
|
#include "nvim/os_unix.h"
|
||||||
|
603
src/nvim/misc1.c
603
src/nvim/misc1.c
@ -47,7 +47,6 @@
|
|||||||
#include "nvim/mouse.h"
|
#include "nvim/mouse.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/os_unix.h"
|
#include "nvim/os_unix.h"
|
||||||
#include "nvim/path.h"
|
|
||||||
#include "nvim/quickfix.h"
|
#include "nvim/quickfix.h"
|
||||||
#include "nvim/regexp.h"
|
#include "nvim/regexp.h"
|
||||||
#include "nvim/screen.h"
|
#include "nvim/screen.h"
|
||||||
@ -2608,54 +2607,7 @@ void vim_beep(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* To get the "real" home directory:
|
|
||||||
* - get value of $HOME
|
|
||||||
* For Unix:
|
|
||||||
* - go to that directory
|
|
||||||
* - do os_dirname() to get the real name of that directory.
|
|
||||||
* This also works with mounts and links.
|
|
||||||
* Don't do this for MS-DOS, it will change the "current dir" for a drive.
|
|
||||||
*/
|
|
||||||
static char_u *homedir = NULL;
|
|
||||||
|
|
||||||
void init_homedir(void)
|
|
||||||
{
|
|
||||||
char_u *var;
|
|
||||||
|
|
||||||
/* In case we are called a second time (when 'encoding' changes). */
|
|
||||||
free(homedir);
|
|
||||||
homedir = NULL;
|
|
||||||
|
|
||||||
var = (char_u *)os_getenv("HOME");
|
|
||||||
|
|
||||||
if (var != NULL && *var == NUL) /* empty is same as not set */
|
|
||||||
var = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
if (var != NULL) {
|
|
||||||
#ifdef UNIX
|
|
||||||
/*
|
|
||||||
* Change to the directory and get the actual path. This resolves
|
|
||||||
* links. Don't do it when we can't return.
|
|
||||||
*/
|
|
||||||
if (os_dirname(NameBuff, MAXPATHL) == OK
|
|
||||||
&& os_chdir((char *)NameBuff) == 0) {
|
|
||||||
if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK)
|
|
||||||
var = IObuff;
|
|
||||||
if (os_chdir((char *)NameBuff) != 0)
|
|
||||||
EMSG(_(e_prev_dir));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
homedir = vim_strsave(var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(EXITFREE)
|
#if defined(EXITFREE)
|
||||||
void free_homedir(void)
|
|
||||||
{
|
|
||||||
free(homedir);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_users(void)
|
void free_users(void)
|
||||||
{
|
{
|
||||||
@ -2664,430 +2616,6 @@ void free_users(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Call expand_env() and store the result in an allocated string.
|
|
||||||
* This is not very memory efficient, this expects the result to be freed
|
|
||||||
* again soon.
|
|
||||||
*/
|
|
||||||
char_u *expand_env_save(char_u *src)
|
|
||||||
{
|
|
||||||
return expand_env_save_opt(src, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Idem, but when "one" is TRUE handle the string as one file name, only
|
|
||||||
* expand "~" at the start.
|
|
||||||
*/
|
|
||||||
char_u *expand_env_save_opt(char_u *src, int one)
|
|
||||||
{
|
|
||||||
char_u *p = xmalloc(MAXPATHL);
|
|
||||||
expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Expand environment variable with path name.
|
|
||||||
* "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
|
|
||||||
* Skips over "\ ", "\~" and "\$" (not for Win32 though).
|
|
||||||
* If anything fails no expansion is done and dst equals src.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
expand_env (
|
|
||||||
char_u *src, /* input string e.g. "$HOME/vim.hlp" */
|
|
||||||
char_u *dst, /* where to put the result */
|
|
||||||
int dstlen /* maximum length of the result */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
expand_env_esc (
|
|
||||||
char_u *srcp, /* input string e.g. "$HOME/vim.hlp" */
|
|
||||||
char_u *dst, /* where to put the result */
|
|
||||||
int dstlen, /* maximum length of the result */
|
|
||||||
int esc, /* escape spaces in expanded variables */
|
|
||||||
int one, /* "srcp" is one file name */
|
|
||||||
char_u *startstr /* start again after this (can be NULL) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
char_u *src;
|
|
||||||
char_u *tail;
|
|
||||||
int c;
|
|
||||||
char_u *var;
|
|
||||||
int copy_char;
|
|
||||||
int mustfree; /* var was allocated, need to free it later */
|
|
||||||
int at_start = TRUE; /* at start of a name */
|
|
||||||
int startstr_len = 0;
|
|
||||||
|
|
||||||
if (startstr != NULL)
|
|
||||||
startstr_len = (int)STRLEN(startstr);
|
|
||||||
|
|
||||||
src = skipwhite(srcp);
|
|
||||||
--dstlen; /* leave one char space for "\," */
|
|
||||||
while (*src && dstlen > 0) {
|
|
||||||
copy_char = TRUE;
|
|
||||||
if ((*src == '$'
|
|
||||||
)
|
|
||||||
|| (*src == '~' && at_start)) {
|
|
||||||
mustfree = FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The variable name is copied into dst temporarily, because it may
|
|
||||||
* be a string in read-only memory and a NUL needs to be appended.
|
|
||||||
*/
|
|
||||||
if (*src != '~') { /* environment var */
|
|
||||||
tail = src + 1;
|
|
||||||
var = dst;
|
|
||||||
c = dstlen - 1;
|
|
||||||
|
|
||||||
#ifdef UNIX
|
|
||||||
/* Unix has ${var-name} type environment vars */
|
|
||||||
if (*tail == '{' && !vim_isIDc('{')) {
|
|
||||||
tail++; /* ignore '{' */
|
|
||||||
while (c-- > 0 && *tail && *tail != '}')
|
|
||||||
*var++ = *tail++;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
while (c-- > 0 && *tail != NUL && ((vim_isIDc(*tail))
|
|
||||||
)) {
|
|
||||||
*var++ = *tail++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(MSWIN) || defined(UNIX)
|
|
||||||
# ifdef UNIX
|
|
||||||
if (src[1] == '{' && *tail != '}')
|
|
||||||
# else
|
|
||||||
if (*src == '%' && *tail != '%')
|
|
||||||
# endif
|
|
||||||
var = NULL;
|
|
||||||
else {
|
|
||||||
# ifdef UNIX
|
|
||||||
if (src[1] == '{')
|
|
||||||
# else
|
|
||||||
if (*src == '%')
|
|
||||||
#endif
|
|
||||||
++tail;
|
|
||||||
#endif
|
|
||||||
*var = NUL;
|
|
||||||
var = vim_getenv(dst, &mustfree);
|
|
||||||
#if defined(MSWIN) || defined(UNIX)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* home directory */
|
|
||||||
else if ( src[1] == NUL
|
|
||||||
|| vim_ispathsep(src[1])
|
|
||||||
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
|
|
||||||
var = homedir;
|
|
||||||
tail = src + 1;
|
|
||||||
} else { /* user directory */
|
|
||||||
#if defined(UNIX)
|
|
||||||
/*
|
|
||||||
* Copy ~user to dst[], so we can put a NUL after it.
|
|
||||||
*/
|
|
||||||
tail = src;
|
|
||||||
var = dst;
|
|
||||||
c = dstlen - 1;
|
|
||||||
while ( c-- > 0
|
|
||||||
&& *tail
|
|
||||||
&& vim_isfilec(*tail)
|
|
||||||
&& !vim_ispathsep(*tail))
|
|
||||||
*var++ = *tail++;
|
|
||||||
*var = NUL;
|
|
||||||
/*
|
|
||||||
* Use os_get_user_directory() to get the user directory.
|
|
||||||
* If this function fails, the shell is used to
|
|
||||||
* expand ~user. This is slower and may fail if the shell
|
|
||||||
* does not support ~user (old versions of /bin/sh).
|
|
||||||
*/
|
|
||||||
var = (char_u *)os_get_user_directory((char *)dst + 1);
|
|
||||||
mustfree = TRUE;
|
|
||||||
if (var == NULL)
|
|
||||||
{
|
|
||||||
expand_T xpc;
|
|
||||||
|
|
||||||
ExpandInit(&xpc);
|
|
||||||
xpc.xp_context = EXPAND_FILES;
|
|
||||||
var = ExpandOne(&xpc, dst, NULL,
|
|
||||||
WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
|
|
||||||
mustfree = TRUE;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* cannot expand user's home directory, so don't try */
|
|
||||||
var = NULL;
|
|
||||||
tail = (char_u *)""; /* for gcc */
|
|
||||||
#endif /* UNIX */
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BACKSLASH_IN_FILENAME
|
|
||||||
/* If 'shellslash' is set change backslashes to forward slashes.
|
|
||||||
* Can't use slash_adjust(), p_ssl may be set temporarily. */
|
|
||||||
if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) {
|
|
||||||
char_u *p = vim_strsave(var);
|
|
||||||
|
|
||||||
if (mustfree) {
|
|
||||||
free(var);
|
|
||||||
}
|
|
||||||
var = p;
|
|
||||||
mustfree = TRUE;
|
|
||||||
forward_slash(var);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If "var" contains white space, escape it with a backslash.
|
|
||||||
* Required for ":e ~/tt" when $HOME includes a space. */
|
|
||||||
if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
|
|
||||||
char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
|
|
||||||
|
|
||||||
if (mustfree)
|
|
||||||
free(var);
|
|
||||||
var = p;
|
|
||||||
mustfree = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (var != NULL && *var != NUL
|
|
||||||
&& (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) {
|
|
||||||
STRCPY(dst, var);
|
|
||||||
dstlen -= (int)STRLEN(var);
|
|
||||||
c = (int)STRLEN(var);
|
|
||||||
/* if var[] ends in a path separator and tail[] starts
|
|
||||||
* with it, skip a character */
|
|
||||||
if (*var != NUL && after_pathsep(dst, dst + c)
|
|
||||||
#if defined(BACKSLASH_IN_FILENAME)
|
|
||||||
&& dst[-1] != ':'
|
|
||||||
#endif
|
|
||||||
&& vim_ispathsep(*tail))
|
|
||||||
++tail;
|
|
||||||
dst += c;
|
|
||||||
src = tail;
|
|
||||||
copy_char = FALSE;
|
|
||||||
}
|
|
||||||
if (mustfree)
|
|
||||||
free(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_char) { /* copy at least one char */
|
|
||||||
/*
|
|
||||||
* Recognize the start of a new name, for '~'.
|
|
||||||
* Don't do this when "one" is TRUE, to avoid expanding "~" in
|
|
||||||
* ":edit foo ~ foo".
|
|
||||||
*/
|
|
||||||
at_start = FALSE;
|
|
||||||
if (src[0] == '\\' && src[1] != NUL) {
|
|
||||||
*dst++ = *src++;
|
|
||||||
--dstlen;
|
|
||||||
} else if ((src[0] == ' ' || src[0] == ',') && !one)
|
|
||||||
at_start = TRUE;
|
|
||||||
*dst++ = *src++;
|
|
||||||
--dstlen;
|
|
||||||
|
|
||||||
if (startstr != NULL && src - startstr_len >= srcp
|
|
||||||
&& STRNCMP(src - startstr_len, startstr, startstr_len) == 0)
|
|
||||||
at_start = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dst = NUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Vim's version of getenv().
|
|
||||||
* Special handling of $HOME, $VIM and $VIMRUNTIME.
|
|
||||||
* Also does ACP to 'enc' conversion for Win32.
|
|
||||||
* "mustfree" is set to TRUE when returned is allocated, it must be
|
|
||||||
* initialized to FALSE by the caller.
|
|
||||||
*/
|
|
||||||
char_u *vim_getenv(char_u *name, int *mustfree)
|
|
||||||
{
|
|
||||||
char_u *p;
|
|
||||||
char_u *pend;
|
|
||||||
int vimruntime;
|
|
||||||
|
|
||||||
|
|
||||||
p = (char_u *)os_getenv((char *)name);
|
|
||||||
if (p != NULL && *p == NUL) /* empty is the same as not set */
|
|
||||||
p = NULL;
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
|
|
||||||
if (!vimruntime && STRCMP(name, "VIM") != 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM.
|
|
||||||
* Don't do this when default_vimruntime_dir is non-empty.
|
|
||||||
*/
|
|
||||||
if (vimruntime
|
|
||||||
#ifdef HAVE_PATHDEF
|
|
||||||
&& *default_vimruntime_dir == NUL
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
p = (char_u *)os_getenv("VIM");
|
|
||||||
if (p != NULL && *p == NUL) /* empty is the same as not set */
|
|
||||||
p = NULL;
|
|
||||||
if (p != NULL) {
|
|
||||||
p = vim_version_dir(p);
|
|
||||||
if (p != NULL)
|
|
||||||
*mustfree = TRUE;
|
|
||||||
else
|
|
||||||
p = (char_u *)os_getenv("VIM");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When expanding $VIM or $VIMRUNTIME fails, try using:
|
|
||||||
* - the directory name from 'helpfile' (unless it contains '$')
|
|
||||||
* - the executable name from argv[0]
|
|
||||||
*/
|
|
||||||
if (p == NULL) {
|
|
||||||
if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL)
|
|
||||||
p = p_hf;
|
|
||||||
if (p != NULL) {
|
|
||||||
/* remove the file name */
|
|
||||||
pend = path_tail(p);
|
|
||||||
|
|
||||||
/* remove "doc/" from 'helpfile', if present */
|
|
||||||
if (p == p_hf)
|
|
||||||
pend = remove_tail(p, pend, (char_u *)"doc");
|
|
||||||
|
|
||||||
/* for $VIM, remove "runtime/" or "vim54/", if present */
|
|
||||||
if (!vimruntime) {
|
|
||||||
pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME);
|
|
||||||
pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove trailing path separator */
|
|
||||||
/* With MacOS path (with colons) the final colon is required */
|
|
||||||
/* to avoid confusion between absolute and relative path */
|
|
||||||
if (pend > p && after_pathsep(p, pend))
|
|
||||||
--pend;
|
|
||||||
|
|
||||||
/* check that the result is a directory name */
|
|
||||||
p = vim_strnsave(p, (int)(pend - p));
|
|
||||||
|
|
||||||
if (!os_isdir(p)) {
|
|
||||||
free(p);
|
|
||||||
p = NULL;
|
|
||||||
} else {
|
|
||||||
*mustfree = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_PATHDEF
|
|
||||||
/* When there is a pathdef.c file we can use default_vim_dir and
|
|
||||||
* default_vimruntime_dir */
|
|
||||||
if (p == NULL) {
|
|
||||||
/* Only use default_vimruntime_dir when it is not empty */
|
|
||||||
if (vimruntime && *default_vimruntime_dir != NUL) {
|
|
||||||
p = default_vimruntime_dir;
|
|
||||||
*mustfree = FALSE;
|
|
||||||
} else if (*default_vim_dir != NUL) {
|
|
||||||
if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL)
|
|
||||||
*mustfree = TRUE;
|
|
||||||
else {
|
|
||||||
p = default_vim_dir;
|
|
||||||
*mustfree = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the environment variable, so that the new value can be found fast
|
|
||||||
* next time, and others can also use it (e.g. Perl).
|
|
||||||
*/
|
|
||||||
if (p != NULL) {
|
|
||||||
if (vimruntime) {
|
|
||||||
vim_setenv((char_u *)"VIMRUNTIME", p);
|
|
||||||
didset_vimruntime = TRUE;
|
|
||||||
} else {
|
|
||||||
vim_setenv((char_u *)"VIM", p);
|
|
||||||
didset_vim = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the directory "vimdir/<version>" or "vimdir/runtime" exists.
|
|
||||||
* Return NULL if not, return its name in allocated memory otherwise.
|
|
||||||
*/
|
|
||||||
static char_u *vim_version_dir(char_u *vimdir)
|
|
||||||
{
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
if (vimdir == NULL || *vimdir == NUL)
|
|
||||||
return NULL;
|
|
||||||
p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE);
|
|
||||||
if (os_isdir(p))
|
|
||||||
return p;
|
|
||||||
free(p);
|
|
||||||
p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE);
|
|
||||||
if (os_isdir(p))
|
|
||||||
return p;
|
|
||||||
free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the string between "p" and "pend" ends in "name/", return "pend" minus
|
|
||||||
* the length of "name/". Otherwise return "pend".
|
|
||||||
*/
|
|
||||||
static char_u *remove_tail(char_u *p, char_u *pend, char_u *name)
|
|
||||||
{
|
|
||||||
int len = (int)STRLEN(name) + 1;
|
|
||||||
char_u *newend = pend - len;
|
|
||||||
|
|
||||||
if (newend >= p
|
|
||||||
&& fnamencmp(newend, name, len - 1) == 0
|
|
||||||
&& (newend == p || after_pathsep(p, newend)))
|
|
||||||
return newend;
|
|
||||||
return pend;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Our portable version of setenv.
|
|
||||||
*/
|
|
||||||
void vim_setenv(char_u *name, char_u *val)
|
|
||||||
{
|
|
||||||
os_setenv((char *)name, (char *)val, 1);
|
|
||||||
/*
|
|
||||||
* When setting $VIMRUNTIME adjust the directory to find message
|
|
||||||
* translations to $VIMRUNTIME/lang.
|
|
||||||
*/
|
|
||||||
if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) {
|
|
||||||
char_u *buf = concat_str(val, (char_u *)"/lang");
|
|
||||||
bindtextdomain(VIMPACKAGE, (char *)buf);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function given to ExpandGeneric() to obtain an environment variable name.
|
|
||||||
*/
|
|
||||||
char_u *get_env_name(expand_T *xp, int idx)
|
|
||||||
{
|
|
||||||
# define ENVNAMELEN 100
|
|
||||||
// this static buffer is needed to avoid a memory leak in ExpandGeneric
|
|
||||||
static char_u name[ENVNAMELEN];
|
|
||||||
char *envname = os_getenvname_at_index(idx);
|
|
||||||
if (envname) {
|
|
||||||
STRLCPY(name, envname, ENVNAMELEN);
|
|
||||||
free(envname);
|
|
||||||
return name;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find all user names for user completion.
|
* Find all user names for user completion.
|
||||||
* Done only once and then cached.
|
* Done only once and then cached.
|
||||||
@ -3137,137 +2665,6 @@ int match_user(char_u *name)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Replace home directory by "~" in each space or comma separated file name in
|
|
||||||
* 'src'.
|
|
||||||
* If anything fails (except when out of space) dst equals src.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
home_replace (
|
|
||||||
buf_T *buf, /* when not NULL, check for help files */
|
|
||||||
char_u *src, /* input file name */
|
|
||||||
char_u *dst, /* where to put the result */
|
|
||||||
int dstlen, /* maximum length of the result */
|
|
||||||
int one /* if TRUE, only replace one file name, include
|
|
||||||
spaces and commas in the file name. */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
size_t dirlen = 0, envlen = 0;
|
|
||||||
size_t len;
|
|
||||||
char_u *homedir_env, *homedir_env_orig;
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
if (src == NULL) {
|
|
||||||
*dst = NUL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the file is a help file, remove the path completely.
|
|
||||||
*/
|
|
||||||
if (buf != NULL && buf->b_help) {
|
|
||||||
STRCPY(dst, path_tail(src));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We check both the value of the $HOME environment variable and the
|
|
||||||
* "real" home directory.
|
|
||||||
*/
|
|
||||||
if (homedir != NULL)
|
|
||||||
dirlen = STRLEN(homedir);
|
|
||||||
|
|
||||||
homedir_env_orig = homedir_env = (char_u *)os_getenv("HOME");
|
|
||||||
/* Empty is the same as not set. */
|
|
||||||
if (homedir_env != NULL && *homedir_env == NUL)
|
|
||||||
homedir_env = NULL;
|
|
||||||
|
|
||||||
if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) {
|
|
||||||
int usedlen = 0;
|
|
||||||
int flen;
|
|
||||||
char_u *fbuf = NULL;
|
|
||||||
|
|
||||||
flen = (int)STRLEN(homedir_env);
|
|
||||||
(void)modify_fname((char_u *)":p", &usedlen,
|
|
||||||
&homedir_env, &fbuf, &flen);
|
|
||||||
flen = (int)STRLEN(homedir_env);
|
|
||||||
if (flen > 0 && vim_ispathsep(homedir_env[flen - 1]))
|
|
||||||
/* Remove the trailing / that is added to a directory. */
|
|
||||||
homedir_env[flen - 1] = NUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homedir_env != NULL)
|
|
||||||
envlen = STRLEN(homedir_env);
|
|
||||||
|
|
||||||
if (!one)
|
|
||||||
src = skipwhite(src);
|
|
||||||
while (*src && dstlen > 0) {
|
|
||||||
/*
|
|
||||||
* Here we are at the beginning of a file name.
|
|
||||||
* First, check to see if the beginning of the file name matches
|
|
||||||
* $HOME or the "real" home directory. Check that there is a '/'
|
|
||||||
* after the match (so that if e.g. the file is "/home/pieter/bla",
|
|
||||||
* and the home directory is "/home/piet", the file does not end up
|
|
||||||
* as "~er/bla" (which would seem to indicate the file "bla" in user
|
|
||||||
* er's home directory)).
|
|
||||||
*/
|
|
||||||
p = homedir;
|
|
||||||
len = dirlen;
|
|
||||||
for (;; ) {
|
|
||||||
if ( len
|
|
||||||
&& fnamencmp(src, p, len) == 0
|
|
||||||
&& (vim_ispathsep(src[len])
|
|
||||||
|| (!one && (src[len] == ',' || src[len] == ' '))
|
|
||||||
|| src[len] == NUL)) {
|
|
||||||
src += len;
|
|
||||||
if (--dstlen > 0)
|
|
||||||
*dst++ = '~';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If it's just the home directory, add "/".
|
|
||||||
*/
|
|
||||||
if (!vim_ispathsep(src[0]) && --dstlen > 0)
|
|
||||||
*dst++ = '/';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p == homedir_env)
|
|
||||||
break;
|
|
||||||
p = homedir_env;
|
|
||||||
len = envlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if (!one) skip to separator: space or comma */
|
|
||||||
while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0)
|
|
||||||
*dst++ = *src++;
|
|
||||||
/* skip separator */
|
|
||||||
while ((*src == ' ' || *src == ',') && --dstlen > 0)
|
|
||||||
*dst++ = *src++;
|
|
||||||
}
|
|
||||||
/* if (dstlen == 0) out of space, what to do??? */
|
|
||||||
|
|
||||||
*dst = NUL;
|
|
||||||
|
|
||||||
if (homedir_env != homedir_env_orig)
|
|
||||||
free(homedir_env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Like home_replace, store the replaced string in allocated memory.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
home_replace_save (
|
|
||||||
buf_T *buf, /* when not NULL, check for help files */
|
|
||||||
char_u *src /* input file name */
|
|
||||||
) FUNC_ATTR_NONNULL_RET
|
|
||||||
{
|
|
||||||
size_t len = 3; /* space for "~/" and trailing NUL */
|
|
||||||
if (src != NULL) /* just in case */
|
|
||||||
len += STRLEN(src);
|
|
||||||
char_u *dst = xmalloc(len);
|
|
||||||
home_replace(buf, src, dst, (int)len, TRUE);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Preserve files and exit.
|
* Preserve files and exit.
|
||||||
* When called IObuff must contain a message.
|
* When called IObuff must contain a message.
|
||||||
|
@ -1802,7 +1802,7 @@ void set_init_1(void)
|
|||||||
# endif
|
# endif
|
||||||
int len;
|
int len;
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
int mustfree;
|
bool mustfree;
|
||||||
|
|
||||||
ga_init(&ga, 1, 100);
|
ga_init(&ga, 1, 100);
|
||||||
for (size_t n = 0; n < ARRAY_SIZE(names); ++n) {
|
for (size_t n = 0; n < ARRAY_SIZE(names); ++n) {
|
||||||
@ -1859,7 +1859,7 @@ void set_init_1(void)
|
|||||||
char_u *buf;
|
char_u *buf;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
int mustfree = FALSE;
|
bool mustfree = false;
|
||||||
|
|
||||||
/* Initialize the 'cdpath' option's default value. */
|
/* Initialize the 'cdpath' option's default value. */
|
||||||
cdpath = vim_getenv((char_u *)"CDPATH", &mustfree);
|
cdpath = vim_getenv((char_u *)"CDPATH", &mustfree);
|
||||||
@ -7426,7 +7426,7 @@ static void paste_option_changed(void)
|
|||||||
*/
|
*/
|
||||||
void vimrc_found(char_u *fname, char_u *envname)
|
void vimrc_found(char_u *fname, char_u *envname)
|
||||||
{
|
{
|
||||||
int dofree = FALSE;
|
bool dofree = false;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
if (fname != NULL) {
|
if (fname != NULL) {
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
// env.c -- environment variable access
|
// env.c -- environment variable access
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
|
// vim.h must be included before charset.h (and possibly others) or things
|
||||||
|
// blow up
|
||||||
|
#include "nvim/vim.h"
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
|
#include "nvim/charset.h"
|
||||||
#include "nvim/os/os.h"
|
#include "nvim/os/os.h"
|
||||||
|
#include "nvim/memory.h"
|
||||||
|
#include "nvim/message.h"
|
||||||
#include "nvim/misc2.h"
|
#include "nvim/misc2.h"
|
||||||
|
#include "nvim/path.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
|
#include "nvim/eval.h"
|
||||||
|
#include "nvim/ex_getln.h"
|
||||||
|
#include "nvim/version.h"
|
||||||
|
|
||||||
#ifdef HAVE__NSGETENVIRON
|
#ifdef HAVE__NSGETENVIRON
|
||||||
#include <crt_externs.h>
|
#include <crt_externs.h>
|
||||||
@ -87,3 +99,589 @@ void os_get_hostname(char *hostname, size_t len)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// To get the "real" home directory:
|
||||||
|
/// - get value of $HOME
|
||||||
|
/// For Unix:
|
||||||
|
/// - go to that directory
|
||||||
|
/// - do os_dirname() to get the real name of that directory.
|
||||||
|
/// This also works with mounts and links.
|
||||||
|
/// Don't do this for MS-DOS, it will change the "current dir" for a drive.
|
||||||
|
static char_u *homedir = NULL;
|
||||||
|
|
||||||
|
void init_homedir(void)
|
||||||
|
{
|
||||||
|
char_u *var;
|
||||||
|
|
||||||
|
/* In case we are called a second time (when 'encoding' changes). */
|
||||||
|
free(homedir);
|
||||||
|
homedir = NULL;
|
||||||
|
|
||||||
|
var = (char_u *)os_getenv("HOME");
|
||||||
|
|
||||||
|
if (var != NULL && *var == NUL) /* empty is same as not set */
|
||||||
|
var = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if (var != NULL) {
|
||||||
|
#ifdef UNIX
|
||||||
|
/*
|
||||||
|
* Change to the directory and get the actual path. This resolves
|
||||||
|
* links. Don't do it when we can't return.
|
||||||
|
*/
|
||||||
|
if (os_dirname(NameBuff, MAXPATHL) == OK
|
||||||
|
&& os_chdir((char *)NameBuff) == 0) {
|
||||||
|
if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK)
|
||||||
|
var = IObuff;
|
||||||
|
if (os_chdir((char *)NameBuff) != 0)
|
||||||
|
EMSG(_(e_prev_dir));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
homedir = vim_strsave(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EXITFREE)
|
||||||
|
|
||||||
|
void free_homedir(void)
|
||||||
|
{
|
||||||
|
free(homedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Call expand_env() and store the result in an allocated string.
|
||||||
|
/// This is not very memory efficient, this expects the result to be freed
|
||||||
|
/// again soon.
|
||||||
|
/// @param src String containing environment variables to expand
|
||||||
|
/// @see {expand_env}
|
||||||
|
char_u *expand_env_save(char_u *src)
|
||||||
|
{
|
||||||
|
return expand_env_save_opt(src, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Similar to expand_env_save() but when "one" is `true` handle the string as
|
||||||
|
/// one file name, i.e. only expand "~" at the start.
|
||||||
|
/// @param src String containing environment variables to expand
|
||||||
|
/// @param one Should treat as only one file name
|
||||||
|
/// @see {expand_env}
|
||||||
|
char_u *expand_env_save_opt(char_u *src, bool one)
|
||||||
|
{
|
||||||
|
char_u *p = xmalloc(MAXPATHL);
|
||||||
|
expand_env_esc(src, p, MAXPATHL, false, one, NULL);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Expand environment variable with path name.
|
||||||
|
/// "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
|
||||||
|
/// Skips over "\ ", "\~" and "\$" (not for Win32 though).
|
||||||
|
/// If anything fails no expansion is done and dst equals src.
|
||||||
|
/// @param src Input string e.g. "$HOME/vim.hlp"
|
||||||
|
/// @param dst Where to put the result
|
||||||
|
/// @param dstlen Maximum length of the result
|
||||||
|
void expand_env(char_u *src, char_u *dst, int dstlen)
|
||||||
|
{
|
||||||
|
expand_env_esc(src, dst, dstlen, false, false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Expand environment variable with path name and escaping.
|
||||||
|
/// "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
|
||||||
|
/// Skips over "\ ", "\~" and "\$" (not for Win32 though).
|
||||||
|
/// If anything fails no expansion is done and dst equals src.
|
||||||
|
/// startstr recognize the start of a new name, for '~' expansion.
|
||||||
|
/// @param srcp Input string e.g. "$HOME/vim.hlp"
|
||||||
|
/// @param dst Where to put the result
|
||||||
|
/// @param dstlen Maximum length of the result
|
||||||
|
/// @param esc Should we escape spaces in expanded variables?
|
||||||
|
/// @param one Should we expand more than one '~'?
|
||||||
|
/// @param startstr Common prefix for paths, can be NULL
|
||||||
|
void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
|
||||||
|
char_u *startstr)
|
||||||
|
{
|
||||||
|
char_u *src;
|
||||||
|
char_u *tail;
|
||||||
|
int c;
|
||||||
|
char_u *var;
|
||||||
|
bool copy_char;
|
||||||
|
bool mustfree; /* var was allocated, need to free it later */
|
||||||
|
bool at_start = true; /* at start of a name */
|
||||||
|
int startstr_len = 0;
|
||||||
|
|
||||||
|
if (startstr != NULL)
|
||||||
|
startstr_len = (int)STRLEN(startstr);
|
||||||
|
|
||||||
|
src = skipwhite(srcp);
|
||||||
|
--dstlen; /* leave one char space for "\," */
|
||||||
|
while (*src && dstlen > 0) {
|
||||||
|
copy_char = true;
|
||||||
|
if ((*src == '$') || (*src == '~' && at_start)) {
|
||||||
|
mustfree = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The variable name is copied into dst temporarily, because it may
|
||||||
|
* be a string in read-only memory and a NUL needs to be appended.
|
||||||
|
*/
|
||||||
|
if (*src != '~') { /* environment var */
|
||||||
|
tail = src + 1;
|
||||||
|
var = dst;
|
||||||
|
c = dstlen - 1;
|
||||||
|
|
||||||
|
#ifdef UNIX
|
||||||
|
/* Unix has ${var-name} type environment vars */
|
||||||
|
if (*tail == '{' && !vim_isIDc('{')) {
|
||||||
|
tail++; /* ignore '{' */
|
||||||
|
while (c-- > 0 && *tail && *tail != '}')
|
||||||
|
*var++ = *tail++;
|
||||||
|
} else // NOLINT
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
while (c-- > 0 && *tail != NUL && vim_isIDc(*tail)) {
|
||||||
|
*var++ = *tail++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(UNIX)
|
||||||
|
// Verify that we have found the end of a UNIX ${VAR} style variable
|
||||||
|
if (src[1] == '{' && *tail != '}') {
|
||||||
|
var = NULL;
|
||||||
|
} else if (src[1] == '{') {
|
||||||
|
++tail;
|
||||||
|
}
|
||||||
|
#elif defined(MSWIN)
|
||||||
|
// Verify that we have found the end of a Windows %VAR% style variable
|
||||||
|
if (src[0] == '%' && *tail != '%') {
|
||||||
|
var = NULL;
|
||||||
|
} else if (src[0] == '%') {
|
||||||
|
++tail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*var = NUL;
|
||||||
|
var = vim_getenv(dst, &mustfree);
|
||||||
|
} else if ( src[1] == NUL /* home directory */
|
||||||
|
|| vim_ispathsep(src[1])
|
||||||
|
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
|
||||||
|
var = homedir;
|
||||||
|
tail = src + 1;
|
||||||
|
} else { /* user directory */
|
||||||
|
#if defined(UNIX)
|
||||||
|
/*
|
||||||
|
* Copy ~user to dst[], so we can put a NUL after it.
|
||||||
|
*/
|
||||||
|
tail = src;
|
||||||
|
var = dst;
|
||||||
|
c = dstlen - 1;
|
||||||
|
while ( c-- > 0
|
||||||
|
&& *tail
|
||||||
|
&& vim_isfilec(*tail)
|
||||||
|
&& !vim_ispathsep(*tail))
|
||||||
|
*var++ = *tail++;
|
||||||
|
*var = NUL;
|
||||||
|
/*
|
||||||
|
* Use os_get_user_directory() to get the user directory.
|
||||||
|
* If this function fails, the shell is used to
|
||||||
|
* expand ~user. This is slower and may fail if the shell
|
||||||
|
* does not support ~user (old versions of /bin/sh).
|
||||||
|
*/
|
||||||
|
var = (char_u *)os_get_user_directory((char *)dst + 1);
|
||||||
|
mustfree = true;
|
||||||
|
if (var == NULL)
|
||||||
|
{
|
||||||
|
expand_T xpc;
|
||||||
|
|
||||||
|
ExpandInit(&xpc);
|
||||||
|
xpc.xp_context = EXPAND_FILES;
|
||||||
|
var = ExpandOne(&xpc, dst, NULL,
|
||||||
|
WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
|
||||||
|
mustfree = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* cannot expand user's home directory, so don't try */
|
||||||
|
var = NULL;
|
||||||
|
tail = (char_u *)""; /* for gcc */
|
||||||
|
#endif /* UNIX */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
|
/* If 'shellslash' is set change backslashes to forward slashes.
|
||||||
|
* Can't use slash_adjust(), p_ssl may be set temporarily. */
|
||||||
|
if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) {
|
||||||
|
char_u *p = vim_strsave(var);
|
||||||
|
|
||||||
|
if (mustfree) {
|
||||||
|
free(var);
|
||||||
|
}
|
||||||
|
var = p;
|
||||||
|
mustfree = true;
|
||||||
|
forward_slash(var);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If "var" contains white space, escape it with a backslash.
|
||||||
|
* Required for ":e ~/tt" when $HOME includes a space. */
|
||||||
|
if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
|
||||||
|
char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
|
||||||
|
|
||||||
|
if (mustfree)
|
||||||
|
free(var);
|
||||||
|
var = p;
|
||||||
|
mustfree = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var != NULL && *var != NUL
|
||||||
|
&& (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) {
|
||||||
|
STRCPY(dst, var);
|
||||||
|
dstlen -= (int)STRLEN(var);
|
||||||
|
c = (int)STRLEN(var);
|
||||||
|
/* if var[] ends in a path separator and tail[] starts
|
||||||
|
* with it, skip a character */
|
||||||
|
if (*var != NUL && after_pathsep(dst, dst + c)
|
||||||
|
#if defined(BACKSLASH_IN_FILENAME)
|
||||||
|
&& dst[-1] != ':'
|
||||||
|
#endif
|
||||||
|
&& vim_ispathsep(*tail))
|
||||||
|
++tail;
|
||||||
|
dst += c;
|
||||||
|
src = tail;
|
||||||
|
copy_char = false;
|
||||||
|
}
|
||||||
|
if (mustfree)
|
||||||
|
free(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_char) { /* copy at least one char */
|
||||||
|
/*
|
||||||
|
* Recognize the start of a new name, for '~'.
|
||||||
|
* Don't do this when "one" is true, to avoid expanding "~" in
|
||||||
|
* ":edit foo ~ foo".
|
||||||
|
*/
|
||||||
|
at_start = false;
|
||||||
|
if (src[0] == '\\' && src[1] != NUL) {
|
||||||
|
*dst++ = *src++;
|
||||||
|
--dstlen;
|
||||||
|
} else if ((src[0] == ' ' || src[0] == ',') && !one) {
|
||||||
|
at_start = true;
|
||||||
|
}
|
||||||
|
*dst++ = *src++;
|
||||||
|
--dstlen;
|
||||||
|
|
||||||
|
if (startstr != NULL && src - startstr_len >= srcp
|
||||||
|
&& STRNCMP(src - startstr_len, startstr, startstr_len) == 0)
|
||||||
|
at_start = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst = NUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the directory "vimdir/<version>" or "vimdir/runtime" exists.
|
||||||
|
/// Return NULL if not, return its name in allocated memory otherwise.
|
||||||
|
/// @param vimdir directory to test
|
||||||
|
static char_u *vim_version_dir(char_u *vimdir)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
if (vimdir == NULL || *vimdir == NUL)
|
||||||
|
return NULL;
|
||||||
|
p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, true);
|
||||||
|
if (os_isdir(p))
|
||||||
|
return p;
|
||||||
|
free(p);
|
||||||
|
p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, true);
|
||||||
|
if (os_isdir(p))
|
||||||
|
return p;
|
||||||
|
free(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the string between "p" and "pend" ends in "name/", return "pend" minus
|
||||||
|
/// the length of "name/". Otherwise return "pend".
|
||||||
|
static char_u *remove_tail(char_u *p, char_u *pend, char_u *name)
|
||||||
|
{
|
||||||
|
int len = (int)STRLEN(name) + 1;
|
||||||
|
char_u *newend = pend - len;
|
||||||
|
|
||||||
|
if (newend >= p
|
||||||
|
&& fnamencmp(newend, name, len - 1) == 0
|
||||||
|
&& (newend == p || after_pathsep(p, newend)))
|
||||||
|
return newend;
|
||||||
|
return pend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vim's version of getenv().
|
||||||
|
/// Special handling of $HOME, $VIM and $VIMRUNTIME, allowing the user to
|
||||||
|
/// override the vim runtime directory at runtime. Also does ACP to 'enc'
|
||||||
|
/// conversion for Win32.
|
||||||
|
/// @param name Name of environment variable to expand
|
||||||
|
/// @param[out] mustfree Ouput parameter for the caller to determine if they are
|
||||||
|
/// responsible for releasing memory. Must be initialized to false
|
||||||
|
/// by the caller.
|
||||||
|
char_u *vim_getenv(char_u *name, bool *mustfree)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
char_u *pend;
|
||||||
|
int vimruntime;
|
||||||
|
|
||||||
|
|
||||||
|
p = (char_u *)os_getenv((char *)name);
|
||||||
|
if (p != NULL && *p == NUL) /* empty is the same as not set */
|
||||||
|
p = NULL;
|
||||||
|
|
||||||
|
if (p != NULL) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
|
||||||
|
if (!vimruntime && STRCMP(name, "VIM") != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When expanding $VIMRUNTIME fails, try using $VIM/vim<version> or $VIM.
|
||||||
|
* Don't do this when default_vimruntime_dir is non-empty.
|
||||||
|
*/
|
||||||
|
if (vimruntime
|
||||||
|
#ifdef HAVE_PATHDEF
|
||||||
|
&& *default_vimruntime_dir == NUL
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
p = (char_u *)os_getenv("VIM");
|
||||||
|
if (p != NULL && *p == NUL) /* empty is the same as not set */
|
||||||
|
p = NULL;
|
||||||
|
if (p != NULL) {
|
||||||
|
p = vim_version_dir(p);
|
||||||
|
if (p != NULL)
|
||||||
|
*mustfree = true;
|
||||||
|
else
|
||||||
|
p = (char_u *)os_getenv("VIM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When expanding $VIM or $VIMRUNTIME fails, try using:
|
||||||
|
* - the directory name from 'helpfile' (unless it contains '$')
|
||||||
|
* - the executable name from argv[0]
|
||||||
|
*/
|
||||||
|
if (p == NULL) {
|
||||||
|
if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL)
|
||||||
|
p = p_hf;
|
||||||
|
if (p != NULL) {
|
||||||
|
/* remove the file name */
|
||||||
|
pend = path_tail(p);
|
||||||
|
|
||||||
|
/* remove "doc/" from 'helpfile', if present */
|
||||||
|
if (p == p_hf)
|
||||||
|
pend = remove_tail(p, pend, (char_u *)"doc");
|
||||||
|
|
||||||
|
/* for $VIM, remove "runtime/" or "vim54/", if present */
|
||||||
|
if (!vimruntime) {
|
||||||
|
pend = remove_tail(p, pend, (char_u *)RUNTIME_DIRNAME);
|
||||||
|
pend = remove_tail(p, pend, (char_u *)VIM_VERSION_NODOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove trailing path separator */
|
||||||
|
if (pend > p && after_pathsep(p, pend))
|
||||||
|
--pend;
|
||||||
|
|
||||||
|
// check that the result is a directory name
|
||||||
|
assert(pend >= p);
|
||||||
|
p = vim_strnsave(p, (size_t)(pend - p));
|
||||||
|
|
||||||
|
if (!os_isdir(p)) {
|
||||||
|
free(p);
|
||||||
|
p = NULL;
|
||||||
|
} else {
|
||||||
|
*mustfree = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_PATHDEF
|
||||||
|
/* When there is a pathdef.c file we can use default_vim_dir and
|
||||||
|
* default_vimruntime_dir */
|
||||||
|
if (p == NULL) {
|
||||||
|
/* Only use default_vimruntime_dir when it is not empty */
|
||||||
|
if (vimruntime && *default_vimruntime_dir != NUL) {
|
||||||
|
p = default_vimruntime_dir;
|
||||||
|
*mustfree = false;
|
||||||
|
} else if (*default_vim_dir != NUL) {
|
||||||
|
if (vimruntime && (p = vim_version_dir(default_vim_dir)) != NULL) {
|
||||||
|
*mustfree = true;
|
||||||
|
} else {
|
||||||
|
p = default_vim_dir;
|
||||||
|
*mustfree = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the environment variable, so that the new value can be found fast
|
||||||
|
* next time, and others can also use it (e.g. Perl).
|
||||||
|
*/
|
||||||
|
if (p != NULL) {
|
||||||
|
if (vimruntime) {
|
||||||
|
vim_setenv((char_u *)"VIMRUNTIME", p);
|
||||||
|
didset_vimruntime = true;
|
||||||
|
} else {
|
||||||
|
vim_setenv((char_u *)"VIM", p);
|
||||||
|
didset_vim = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace home directory by "~" in each space or comma separated file name in
|
||||||
|
/// 'src'.
|
||||||
|
/// If anything fails (except when out of space) dst equals src.
|
||||||
|
/// @param buf When not NULL, check for help files
|
||||||
|
/// @param src Input file name
|
||||||
|
/// @param dst Where to put the result
|
||||||
|
/// @param dstlen Maximum length of the result
|
||||||
|
/// @param one If true, only replace one file name, including spaces and commas
|
||||||
|
/// in the file name
|
||||||
|
void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one)
|
||||||
|
{
|
||||||
|
size_t dirlen = 0, envlen = 0;
|
||||||
|
size_t len;
|
||||||
|
char_u *homedir_env, *homedir_env_orig;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
if (src == NULL) {
|
||||||
|
*dst = NUL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the file is a help file, remove the path completely.
|
||||||
|
*/
|
||||||
|
if (buf != NULL && buf->b_help) {
|
||||||
|
STRCPY(dst, path_tail(src));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We check both the value of the $HOME environment variable and the
|
||||||
|
* "real" home directory.
|
||||||
|
*/
|
||||||
|
if (homedir != NULL)
|
||||||
|
dirlen = STRLEN(homedir);
|
||||||
|
|
||||||
|
homedir_env_orig = homedir_env = (char_u *)os_getenv("HOME");
|
||||||
|
/* Empty is the same as not set. */
|
||||||
|
if (homedir_env != NULL && *homedir_env == NUL)
|
||||||
|
homedir_env = NULL;
|
||||||
|
|
||||||
|
if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) {
|
||||||
|
int usedlen = 0;
|
||||||
|
int flen;
|
||||||
|
char_u *fbuf = NULL;
|
||||||
|
|
||||||
|
flen = (int)STRLEN(homedir_env);
|
||||||
|
(void)modify_fname((char_u *)":p", &usedlen,
|
||||||
|
&homedir_env, &fbuf, &flen);
|
||||||
|
flen = (int)STRLEN(homedir_env);
|
||||||
|
if (flen > 0 && vim_ispathsep(homedir_env[flen - 1]))
|
||||||
|
/* Remove the trailing / that is added to a directory. */
|
||||||
|
homedir_env[flen - 1] = NUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (homedir_env != NULL)
|
||||||
|
envlen = STRLEN(homedir_env);
|
||||||
|
|
||||||
|
if (!one)
|
||||||
|
src = skipwhite(src);
|
||||||
|
while (*src && dstlen > 0) {
|
||||||
|
/*
|
||||||
|
* Here we are at the beginning of a file name.
|
||||||
|
* First, check to see if the beginning of the file name matches
|
||||||
|
* $HOME or the "real" home directory. Check that there is a '/'
|
||||||
|
* after the match (so that if e.g. the file is "/home/pieter/bla",
|
||||||
|
* and the home directory is "/home/piet", the file does not end up
|
||||||
|
* as "~er/bla" (which would seem to indicate the file "bla" in user
|
||||||
|
* er's home directory)).
|
||||||
|
*/
|
||||||
|
p = homedir;
|
||||||
|
len = dirlen;
|
||||||
|
for (;; ) {
|
||||||
|
if ( len
|
||||||
|
&& fnamencmp(src, p, len) == 0
|
||||||
|
&& (vim_ispathsep(src[len])
|
||||||
|
|| (!one && (src[len] == ',' || src[len] == ' '))
|
||||||
|
|| src[len] == NUL)) {
|
||||||
|
src += len;
|
||||||
|
if (--dstlen > 0)
|
||||||
|
*dst++ = '~';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's just the home directory, add "/".
|
||||||
|
*/
|
||||||
|
if (!vim_ispathsep(src[0]) && --dstlen > 0)
|
||||||
|
*dst++ = '/';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p == homedir_env)
|
||||||
|
break;
|
||||||
|
p = homedir_env;
|
||||||
|
len = envlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if (!one) skip to separator: space or comma */
|
||||||
|
while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0)
|
||||||
|
*dst++ = *src++;
|
||||||
|
/* skip separator */
|
||||||
|
while ((*src == ' ' || *src == ',') && --dstlen > 0)
|
||||||
|
*dst++ = *src++;
|
||||||
|
}
|
||||||
|
/* if (dstlen == 0) out of space, what to do??? */
|
||||||
|
|
||||||
|
*dst = NUL;
|
||||||
|
|
||||||
|
if (homedir_env != homedir_env_orig)
|
||||||
|
free(homedir_env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like home_replace, store the replaced string in allocated memory.
|
||||||
|
/// @param buf When not NULL, check for help files
|
||||||
|
/// @param src Input file name
|
||||||
|
char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
|
||||||
|
{
|
||||||
|
size_t len = 3; /* space for "~/" and trailing NUL */
|
||||||
|
if (src != NULL) /* just in case */
|
||||||
|
len += STRLEN(src);
|
||||||
|
char_u *dst = xmalloc(len);
|
||||||
|
home_replace(buf, src, dst, (int)len, true);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Our portable version of setenv.
|
||||||
|
/// Has special handling for $VIMRUNTIME to keep the localization machinery
|
||||||
|
/// sane.
|
||||||
|
void vim_setenv(char_u *name, char_u *val)
|
||||||
|
{
|
||||||
|
os_setenv((char *)name, (char *)val, 1);
|
||||||
|
/*
|
||||||
|
* When setting $VIMRUNTIME adjust the directory to find message
|
||||||
|
* translations to $VIMRUNTIME/lang.
|
||||||
|
*/
|
||||||
|
if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) {
|
||||||
|
char_u *buf = concat_str(val, (char_u *)"/lang");
|
||||||
|
bindtextdomain(VIMPACKAGE, (char *)buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Function given to ExpandGeneric() to obtain an environment variable name.
|
||||||
|
char_u *get_env_name(expand_T *xp, int idx)
|
||||||
|
{
|
||||||
|
# define ENVNAMELEN 100
|
||||||
|
// this static buffer is needed to avoid a memory leak in ExpandGeneric
|
||||||
|
static char_u name[ENVNAMELEN];
|
||||||
|
assert(idx >= 0);
|
||||||
|
char *envname = os_getenvname_at_index((size_t)idx);
|
||||||
|
if (envname) {
|
||||||
|
STRLCPY(name, envname, ENVNAMELEN);
|
||||||
|
free(envname);
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ local NULL = helpers.NULL
|
|||||||
|
|
||||||
require('lfs')
|
require('lfs')
|
||||||
|
|
||||||
|
-- Needed because expand_env_esc uses the char table
|
||||||
|
helpers.vim_init()
|
||||||
|
|
||||||
local env = cimport('./src/nvim/os/os.h')
|
local env = cimport('./src/nvim/os/os.h')
|
||||||
|
|
||||||
describe('env function', function()
|
describe('env function', function()
|
||||||
@ -127,4 +130,79 @@ describe('env function', function()
|
|||||||
eq(hostname, (ffi.string(hostname_buf)))
|
eq(hostname, (ffi.string(hostname_buf)))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('expand_env_esc', function()
|
||||||
|
it('expands environment variables', function()
|
||||||
|
local name = 'NEOVIM_UNIT_TEST_EXPAND_ENV_ESCN'
|
||||||
|
local value = 'NEOVIM_UNIT_TEST_EXPAND_ENV_ESCV'
|
||||||
|
os_setenv(name, value, 1)
|
||||||
|
-- TODO(bobtwinkles) This only tests UNIX expansions. There should be a
|
||||||
|
-- test for windows as well
|
||||||
|
local input1 = to_cstr('$NEOVIM_UNIT_TEST_EXPAND_ENV_ESCN/test')
|
||||||
|
local input2 = to_cstr('${NEOVIM_UNIT_TEST_EXPAND_ENV_ESCN}/test')
|
||||||
|
local output_buff1 = cstr(255, '')
|
||||||
|
local output_buff2 = cstr(255, '')
|
||||||
|
local output_expected = 'NEOVIM_UNIT_TEST_EXPAND_ENV_ESCV/test'
|
||||||
|
env.expand_env_esc(input1, output_buff1, 255, false, true, NULL)
|
||||||
|
env.expand_env_esc(input2, output_buff2, 255, false, true, NULL)
|
||||||
|
eq(output_expected, ffi.string(output_buff1))
|
||||||
|
eq(output_expected, ffi.string(output_buff2))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('expands ~ once when one is true', function()
|
||||||
|
local input = '~/foo ~ foo'
|
||||||
|
local homedir = cstr(255, '')
|
||||||
|
env.expand_env_esc(to_cstr('~'), homedir, 255, false, true, NULL)
|
||||||
|
local output_expected = ffi.string(homedir) .. "/foo ~ foo"
|
||||||
|
local output = cstr(255, '')
|
||||||
|
env.expand_env_esc(to_cstr(input), output, 255, false, true, NULL)
|
||||||
|
eq(ffi.string(output), ffi.string(output_expected))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('expands ~ every time when one is false', function()
|
||||||
|
local input = to_cstr('~/foo ~ foo')
|
||||||
|
local homedir = cstr(255, '')
|
||||||
|
env.expand_env_esc(to_cstr('~'), homedir, 255, false, true, NULL)
|
||||||
|
homedir = ffi.string(homedir)
|
||||||
|
local output_expected = homedir .. "/foo " .. homedir .. " foo"
|
||||||
|
local output = cstr(255, '')
|
||||||
|
env.expand_env_esc(input, output, 255, false, false, NULL)
|
||||||
|
eq(output_expected, ffi.string(output))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('respects the dstlen parameter without expansion', function()
|
||||||
|
local input = to_cstr('this is a very long thing that will not fit')
|
||||||
|
-- The buffer is long enough to actually contain the full input in case the
|
||||||
|
-- test fails, but we don't tell expand_env_esc that
|
||||||
|
local output = cstr(255, '')
|
||||||
|
env.expand_env_esc(input, output, 5, false, true, NULL)
|
||||||
|
-- Make sure the first few characters are copied properly and that there is a
|
||||||
|
-- terminating null character
|
||||||
|
for i=0,3 do
|
||||||
|
eq(input[i], output[i])
|
||||||
|
end
|
||||||
|
eq(0, output[4])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('respects the dstlen parameter with expansion', function()
|
||||||
|
local varname = to_cstr('NVIM_UNIT_TEST_EXPAND_ENV_ESC_DSTLENN')
|
||||||
|
local varval = to_cstr('NVIM_UNIT_TEST_EXPAND_ENV_ESC_DSTLENV')
|
||||||
|
env.os_setenv(varname, varval, 1)
|
||||||
|
-- TODO(bobtwinkles) This test uses unix-specific environment variable accessing,
|
||||||
|
-- should have some alternative for windows
|
||||||
|
local input = to_cstr('$NVIM_UNIT_TEST_EXPAND_ENV_ESC_DSTLENN/even more stuff')
|
||||||
|
-- The buffer is long enough to actually contain the full input in case the
|
||||||
|
-- test fails, but we don't tell expand_env_esc that
|
||||||
|
local output = cstr(255, '')
|
||||||
|
env.expand_env_esc(input, output, 5, false, true, NULL)
|
||||||
|
-- Make sure the first few characters are copied properly and that there is a
|
||||||
|
-- terminating null character
|
||||||
|
-- expand_env_esc SHOULD NOT expand the variable if there is not enough space to
|
||||||
|
-- contain the result
|
||||||
|
for i=0,3 do
|
||||||
|
eq(output[i], input[i])
|
||||||
|
end
|
||||||
|
eq(output[4], 0)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user