aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/env.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os/env.c')
-rw-r--r--src/nvim/os/env.c267
1 files changed, 159 insertions, 108 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 12c2da6152..7fb4a93b54 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -1,11 +1,11 @@
-// env.c -- environment variable access
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include <assert.h>
+// Environment inspection
+#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"
@@ -14,6 +14,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/path.h"
+#include "nvim/macros.h"
#include "nvim/strings.h"
#include "nvim/eval.h"
#include "nvim/ex_getln.h"
@@ -176,7 +177,7 @@ void os_get_hostname(char *hostname, size_t size)
/// - do os_dirname() to get the real name of that directory.
/// This also works with mounts and links.
/// Don't do this for Windows, it will change the "current dir" for a drive.
-static char_u *homedir = NULL;
+static char *homedir = NULL;
void init_homedir(void)
{
@@ -220,7 +221,7 @@ void init_homedir(void)
}
}
#endif
- homedir = vim_strsave((char_u *)var);
+ homedir = xstrdup(var);
}
}
@@ -357,7 +358,7 @@ void expand_env_esc(char_u *restrict srcp,
} else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
- var = homedir;
+ var = (char_u *)homedir;
tail = src + 1;
} else { // user directory
#if defined(UNIX)
@@ -521,10 +522,11 @@ static char *remove_tail(char *path, char *pend, char *dirname)
return pend;
}
-/// Iterate over colon-separated list
+/// Iterate over a delimited list.
///
/// @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] iter Pointer used for iteration. Must be NULL on first
/// iteration.
@@ -533,18 +535,19 @@ static char *remove_tail(char *path, char *pend, char *dirname)
/// @param[out] len Location where current directory length should be saved.
///
/// @return Next iter argument value or NULL when iteration should stop.
-const void *vim_colon_env_iter(const char *const val,
- const void *const iter,
- const char **const dir,
- size_t *const len)
- FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
+const void *vim_env_iter(const char delim,
+ const char *const val,
+ const void *const iter,
+ const char **const dir,
+ size_t *const len)
+ FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
const char *varval = (const char *) iter;
if (varval == NULL) {
varval = val;
}
*dir = varval;
- const char *const dirend = strchr(varval, ':');
+ const char *const dirend = strchr(varval, delim);
if (dirend == NULL) {
*len = strlen(varval);
return NULL;
@@ -554,10 +557,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.
///
+/// @param[in] delim Delimiter character.
/// @param[in] val Value of the environment variable to iterate over.
/// @param[in] iter Pointer used for iteration. Must be NULL on first
/// iteration.
@@ -566,18 +570,19 @@ const void *vim_colon_env_iter(const char *const val,
/// @param[out] len Location where current directory length should be saved.
///
/// @return Next iter argument value or NULL when iteration should stop.
-const void *vim_colon_env_iter_rev(const char *const val,
- const void *const iter,
- const char **const dir,
- size_t *const len)
- FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
+const void *vim_env_iter_rev(const char delim,
+ const char *const val,
+ const void *const iter,
+ const char **const dir,
+ size_t *const len)
+ FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
const char *varend = (const char *) iter;
if (varend == NULL) {
varend = val + strlen(val) - 1;
}
- const size_t varlen = (size_t) (varend - val) + 1;
- const char *const colon = xmemrchr(val, ':', varlen);
+ const size_t varlen = (size_t)(varend - val) + 1;
+ const char *const colon = xmemrchr(val, (uint8_t)delim, varlen);
if (colon == NULL) {
*len = varlen;
*dir = val;
@@ -596,6 +601,9 @@ const void *vim_colon_env_iter_rev(const char *const val,
/// @param name Environment variable to expand
char *vim_getenv(const char *name)
{
+ // init_path() should have been called before now.
+ assert(get_vim_var_str(VV_PROGPATH)[0] != NUL);
+
const char *kos_env_path = os_getenv(name);
if (kos_env_path != NULL) {
return xstrdup(kos_env_path);
@@ -634,18 +642,17 @@ char *vim_getenv(const char *name)
char exe_name[MAXPATHL];
// Find runtime path relative to the nvim binary: ../share/nvim/runtime
if (vim_path == NULL) {
- size_t exe_name_len = MAXPATHL;
- if (os_exepath(exe_name, &exe_name_len) == 0) {
- char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
- *path_end = '\0'; // remove the trailing "nvim.exe"
- path_end = (char *)path_tail((char_u *)exe_name);
- *path_end = '\0'; // remove the trailing "bin/"
- if (append_path(
- exe_name,
- "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
- MAXPATHL) == OK) {
- vim_path = exe_name;
- }
+ xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH),
+ sizeof(exe_name));
+ char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
+ *path_end = '\0'; // remove the trailing "nvim.exe"
+ path_end = (char *)path_tail((char_u *)exe_name);
+ *path_end = '\0'; // remove the trailing "bin/"
+ if (append_path(
+ exe_name,
+ "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
+ MAXPATHL) == OK) {
+ vim_path = exe_name; // -V507
}
}
@@ -678,6 +685,7 @@ char *vim_getenv(const char *name)
vim_path = NULL;
}
}
+ assert(vim_path != exe_name);
}
#ifdef HAVE_PATHDEF
@@ -712,108 +720,123 @@ char *vim_getenv(const char *name)
/// Replace home directory by "~" in each space or comma separated file name in
/// 'src'.
+///
+/// Replace home directory with tilde in each file name
+///
/// 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(const buf_T *const buf, const char_u *src,
- char_u *dst, size_t dstlen, bool one)
+///
+/// @param[in] buf When not NULL, uses this buffer to check whether it is
+/// a help file. If it is then path to file is removed
+/// completely, `one` is ignored and assumed to be true.
+/// @param[in] src Input file names. Assumed to be a space/comma separated
+/// list unless `one` is true.
+/// @param[out] dst Where to put the result.
+/// @param[in] dstlen Destination length.
+/// @param[in] one If true, assumes source is a single file name and not
+/// a list of them.
+///
+/// @return length of the string put into dst, does not include NUL byte.
+size_t home_replace(const buf_T *const buf, const char_u *src,
+ char_u *const dst, size_t dstlen, const bool one)
+ FUNC_ATTR_NONNULL_ARG(3)
{
- size_t dirlen = 0, envlen = 0;
- size_t len;
+ size_t dirlen = 0;
+ size_t envlen = 0;
if (src == NULL) {
*dst = NUL;
- return;
+ return 0;
}
- /*
- * If the file is a help file, remove the path completely.
- */
if (buf != NULL && buf->b_help) {
- xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
- return;
+ const size_t dlen = xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
+ return MIN(dlen, dstlen - 1);
}
- /*
- * We check both the value of the $HOME environment variable and the
- * "real" home directory.
- */
- if (homedir != NULL)
- dirlen = STRLEN(homedir);
+ // We check both the value of the $HOME environment variable and the
+ // "real" home directory.
+ if (homedir != NULL) {
+ dirlen = strlen(homedir);
+ }
- char_u *homedir_env = (char_u *)os_getenv("HOME");
+ const char *const homedir_env = os_getenv("HOME");
+ char *homedir_env_mod = (char *)homedir_env;
bool must_free = false;
- if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) {
+ if (homedir_env_mod != NULL && strchr(homedir_env_mod, '~') != NULL) {
must_free = true;
size_t usedlen = 0;
- size_t flen = STRLEN(homedir_env);
+ size_t flen = strlen(homedir_env_mod);
char_u *fbuf = NULL;
- (void)modify_fname((char_u *)":p", &usedlen, &homedir_env, &fbuf, &flen);
- flen = 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;
+ (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod,
+ &fbuf, &flen);
+ flen = strlen(homedir_env_mod);
+ assert(homedir_env_mod != homedir_env);
+ if (vim_ispathsep(homedir_env_mod[flen - 1])) {
+ // Remove the trailing / that is added to a directory.
+ homedir_env_mod[flen - 1] = NUL;
+ }
}
- if (homedir_env != NULL)
- envlen = STRLEN(homedir_env);
+ if (homedir_env_mod != NULL) {
+ envlen = strlen(homedir_env_mod);
+ }
- if (!one)
+ if (!one) {
src = skipwhite(src);
+ }
+ char *dst_p = (char *)dst;
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)).
- */
- char_u *p = homedir;
- len = dirlen;
- for (;; ) {
- if ( len
- && fnamencmp(src, p, len) == 0
- && (vim_ispathsep(src[len])
- || (!one && (src[len] == ',' || src[len] == ' '))
- || src[len] == NUL)) {
+ // 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)).
+ char *p = homedir;
+ size_t len = dirlen;
+ for (;;) {
+ if (len
+ && fnamencmp(src, (char_u *)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++ = '/';
+ if (--dstlen > 0) {
+ *dst_p++ = '~';
+ }
+
+ // If it's just the home directory, add "/".
+ if (!vim_ispathsep(src[0]) && --dstlen > 0) {
+ *dst_p++ = '/';
+ }
break;
}
- if (p == homedir_env)
+ if (p == homedir_env_mod) {
break;
- p = homedir_env;
+ }
+ p = homedir_env_mod;
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 (!one) skip to separator: space or comma.
+ while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) {
+ *dst_p++ = (char)(*src++);
+ }
+ // Skip separator.
+ while ((*src == ' ' || *src == ',') && --dstlen > 0) {
+ *dst_p++ = (char)(*src++);
+ }
}
- /* if (dstlen == 0) out of space, what to do??? */
+ // If (dstlen == 0) out of space, what to do???
- *dst = NUL;
+ *dst_p = NUL;
if (must_free) {
- xfree(homedir_env);
+ xfree(homedir_env_mod);
}
+ return (size_t)(dst_p - (char *)dst);
}
/// Like home_replace, store the replaced string in allocated memory.
@@ -879,8 +902,8 @@ bool os_setenv_append_path(const char *fname)
// No prescribed maximum on unix.
# define MAX_ENVPATHLEN INT_MAX
#endif
- if (!path_is_absolute_path((char_u *)fname)) {
- EMSG2(_(e_intern2), "os_setenv_append_path()");
+ if (!path_is_absolute((char_u *)fname)) {
+ internal_error("os_setenv_append_path()");
return false;
}
const char *tail = (char *)path_tail_with_sep((char_u *)fname);
@@ -914,8 +937,36 @@ bool os_term_is_nice(void)
return true;
#else
const char *vte_version = os_getenv("VTE_VERSION");
- return (vte_version && atoi(vte_version) >= 3900)
- || NULL != os_getenv("KONSOLE_PROFILE_NAME")
- || NULL != os_getenv("KONSOLE_DBUS_SESSION");
+ if ((vte_version && atoi(vte_version) >= 3900)
+ || os_getenv("KONSOLE_PROFILE_NAME")
+ || os_getenv("KONSOLE_DBUS_SESSION")) {
+ return true;
+ }
+ const char *termprg = os_getenv("TERM_PROGRAM");
+ if (termprg && striequal(termprg, "iTerm.app")) {
+ return true;
+ }
+ const char *term = os_getenv("TERM");
+ if (term && strncmp(term, "rxvt", 4) == 0) {
+ return true;
+ }
+ return false;
#endif
}
+
+/// Returns true if `sh` looks like it resolves to "cmd.exe".
+bool os_shell_is_cmdexe(const char *sh)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (*sh == NUL) {
+ return false;
+ }
+ if (striequal(sh, "$COMSPEC")) {
+ const char *comspec = os_getenv("COMSPEC");
+ return striequal("cmd.exe", (char *)path_tail((char_u *)comspec));
+ }
+ if (striequal(sh, "cmd.exe") || striequal(sh, "cmd")) {
+ return true;
+ }
+ return striequal("cmd.exe", (char *)path_tail((char_u *)sh));
+}