aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/getchar.c1
-rw-r--r--src/nvim/hardcopy.c1
-rw-r--r--src/nvim/if_cscope.c1
-rw-r--r--src/nvim/log.c1
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mark.c1
-rw-r--r--src/nvim/memfile.c1
-rw-r--r--src/nvim/misc1.c603
-rw-r--r--src/nvim/option.c6
-rw-r--r--src/nvim/os/env.c598
13 files changed, 607 insertions, 616 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 10e2027b00..9e4b110e8b 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1744,7 +1744,7 @@ ex_let_one (
name[len] = NUL;
p = get_tv_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
- int mustfree = FALSE;
+ bool mustfree = false;
char_u *s = vim_getenv(name, &mustfree);
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 *string = NULL;
- int mustfree = FALSE;
+ bool mustfree = false;
int len;
int cc;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 12a634416b..2c674e06e6 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -5059,7 +5059,7 @@ void fix_help_buffer(void)
char_u *fname;
char_u *p;
char_u *rt;
- int mustfree;
+ bool mustfree;
/* set filetype to "help". */
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 238beebf3e..a5d0d0be16 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -3808,7 +3808,7 @@ expand_shellcmd (
char_u *pat;
int i;
char_u *path;
- int mustfree = FALSE;
+ bool mustfree = false;
garray_T ga;
char_u *buf = xmalloc(MAXPATHL);
size_t l;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 96ce586a9e..bb251c102e 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -51,6 +51,7 @@
#include "nvim/undo.h"
#include "nvim/os/event.h"
#include "nvim/os/input.h"
+#include "nvim/os/os.h"
/*
* These buffers are used for storing:
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index f5eed26a2d..b5e7ec414c 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -32,7 +32,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/garray.h"
#include "nvim/option.h"
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index df61afa398..bd9e005676 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -20,7 +20,6 @@
#include "nvim/eval.h"
#include "nvim/fileio.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/memory.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/log.c b/src/nvim/log.c
index e8e0c9bbb9..a3e708aa4d 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -8,7 +8,6 @@
#include <unistd.h>
#include "nvim/log.h"
-#include "nvim/misc1.h"
#include "nvim/types.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 2f1e6e6d3b..0b3402b682 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -818,7 +818,7 @@ static void init_locale(void)
# endif
{
- int mustfree = FALSE;
+ bool mustfree = false;
char_u *p;
/* expand_env() doesn't work yet, because chartab[] is not initialized
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 5fee8a875c..2737380a8e 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -30,7 +30,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/normal.h"
#include "nvim/option.h"
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index baab70ee6a..26542759be 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -56,7 +56,6 @@
#include "nvim/fileio.h"
#include "nvim/memline.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/misc2.h"
#include "nvim/memory.h"
#include "nvim/os_unix.h"
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index c9f3fbd511..5d8b88601e 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -47,7 +47,6 @@
#include "nvim/mouse.h"
#include "nvim/option.h"
#include "nvim/os_unix.h"
-#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.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)
-void free_homedir(void)
-{
- free(homedir);
-}
void free_users(void)
{
@@ -2665,430 +2617,6 @@ void free_users(void)
#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.
* Done only once and then cached.
*/
@@ -3138,137 +2666,6 @@ int match_user(char_u *name)
}
/*
- * 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.
* When called IObuff must contain a message.
* NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 98584d1567..db49f6ba1c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1802,7 +1802,7 @@ void set_init_1(void)
# endif
int len;
garray_T ga;
- int mustfree;
+ bool mustfree;
ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); ++n) {
@@ -1859,7 +1859,7 @@ void set_init_1(void)
char_u *buf;
int i;
int j;
- int mustfree = FALSE;
+ bool mustfree = false;
/* Initialize the 'cdpath' option's default value. */
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)
{
- int dofree = FALSE;
+ bool dofree = false;
char_u *p;
if (fname != NULL) {
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index b2e62453c5..3bea2908d5 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -1,11 +1,23 @@
// env.c -- environment variable access
+#include <assert.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/charset.h"
#include "nvim/os/os.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/misc2.h"
+#include "nvim/path.h"
#include "nvim/strings.h"
+#include "nvim/eval.h"
+#include "nvim/ex_getln.h"
+#include "nvim/version.h"
#ifdef HAVE__NSGETENVIRON
#include <crt_externs.h>
@@ -87,3 +99,589 @@ void os_get_hostname(char *hostname, size_t len)
#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;
+ }
+}
+